/** * PopulateProjects * * Populates the internal list of projects * * @access protected * @throws Exception if file cannot be read */ protected function PopulateProjects() { if (!($fp = fopen($this->projectConfig, 'r'))) { throw new Exception(sprintf(__('Failed to open project list file %1$s'), $this->projectConfig)); } $projectRoot = GitPHP_Util::AddSlash(GitPHP_Config::GetInstance()->GetValue('projectroot')); while (!feof($fp) && ($line = fgets($fp))) { if (preg_match('/^([^\\s]+)(\\s.+)?$/', $line, $regs)) { if (is_file($projectRoot . $regs[1] . '/HEAD')) { try { $projObj = new GitPHP_Project($projectRoot, $regs[1]); if (isset($regs[2]) && !empty($regs[2])) { $projOwner = trim($regs[2]); if (!empty($projOwner)) { $projObj->SetOwner($projOwner); } } $this->projects[$regs[1]] = $projObj; } catch (Exception $e) { GitPHP_Log::GetInstance()->Log($e->getMessage()); } } else { GitPHP_Log::GetInstance()->Log(sprintf('%1$s is not a git project', $projectRoot . $regs[1])); } } } fclose($fp); }
public function testLoadHead() { $strategy = new GitPHP_ProjectLoad_Raw($this->getMockBuilder('GitPHP_GitObjectLoader')->disableOriginalConstructor()->getMock()); $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git'); $headlistmock = $this->getMock('GitPHP_HeadList', array('Exists', 'GetHead'), array($project, $this->getMock('GitPHP_HeadListLoadStrategy_Interface'))); $headmock = $this->getMock('GitPHP_Head', array('GetHash'), array($project, 'master')); $headmock->expects($this->any())->method('GetHash')->will($this->returnValue('1234567890abcdef1234567890ABCDEF12345678')); $headlistmock->expects($this->any())->method('Exists')->with($this->equalTo('master'))->will($this->returnValue(true)); $headlistmock->expects($this->any())->method('GetHead')->with($this->equalTo('master'))->will($this->returnValue($headmock)); $project->SetHeadList($headlistmock); $this->assertEquals('1234567890abcdef1234567890ABCDEF12345678', $strategy->LoadHead($project)); $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepoexported.git'); $this->assertEquals('1234567890abcdef1234567890ABCDEF12345678', $strategy->LoadHead($project)); }
/** * Gets the matching object * * @return GitPHP_Tree|GitPHP_Blob|null matching object */ public function GetObject() { if ($this->objectType == 'tree') { $tree = $this->project->GetObjectManager()->GetTree($this->objectHash); $tree->SetPath($this->path); return $tree; } else { if ($this->objectType == 'blob') { $blob = $this->project->GetObjectManager()->GetBlob($this->objectHash); $blob->SetPath($this->path); return $blob; } } return null; }
/** * Instantiates object * * @param GitPHP_Project $project the project * @param string $hash pack hash * @param GitPHP_GitObjectLoader object loader */ public function __construct($project, $hash, $objectLoader) { if (!$project) { throw new Exception('Project is required'); } if (!preg_match('/[0-9A-Fa-f]{40}/', $hash)) { throw new GitPHP_InvalidHashException($hash); } if (!$objectLoader) { throw new Exception('Object loader is required'); } $this->hash = $hash; $this->packIndex = new GitPHP_PackIndex($project->GetPath() . '/objects/pack/pack-' . $hash . '.idx'); $this->packData = new GitPHP_PackData($project->GetPath() . '/objects/pack/pack-' . $hash . '.pack', $objectLoader); }
/** * Searches file contents for matches */ private function SearchFileContents() { $args = array(); $args[] = '-I'; $args[] = '--full-name'; $args[] = '--ignore-case'; $args[] = '-n'; $args[] = '-e'; $args[] = '"' . addslashes($this->search) . '"'; $args[] = $this->treeHash; $lines = explode("\n", $this->exe->Execute($this->project->GetPath(), GIT_GREP, $args)); foreach ($lines as $line) { if (preg_match('/^[^:]+:([^:]+):([0-9]+):(.+)$/', $line, $regs)) { if (isset($this->allResults[$regs[1]])) { $result = $this->allResults[$regs[1]]; $matchingLines = $result->GetMatchingLines(); $matchingLines[(int) $regs[2]] = trim($regs[3], "\n\r\v"); $result->SetMatchingLines($matchingLines); } else { $tree = $this->GetTree(); $hash = $tree->PathToHash($regs[1]); if ($hash) { $blob = $this->project->GetObjectManager()->GetBlob($hash); $blob->SetPath($regs[1]); $result = new GitPHP_FileSearchResult($this->project, $blob, $regs[1]); $matchingLines = array(); $matchingLines[(int) $regs[2]] = trim($regs[3], "\n\r\v"); $result->SetMatchingLines($matchingLines); $this->allResults[$regs[1]] = $result; } } } } }
/** * Returns the current revision * * @return GitPHP_Commit */ function current() { if (!$this->dataLoaded) { $this->LoadData(); } return $this->project->GetCommit(current($this->hashList)); }
/** * Execute rev-list command * * @param GitPHP_Project $project project * @param string $hash hash to look back from * @param int $count number to return (0 for all) * @param int $skip number of items to skip * @param array $args extra arguments */ public function RevList($project, $hash, $count, $skip = 0, $args = array()) { if (!$project || empty($hash)) { return; } $canSkip = true; if ($skip > 0) { $canSkip = $this->exe->CanSkip(); } $extraargs = array(); if ($canSkip) { if ($count > 0) { $extraargs[] = '--max-count=' . $count; } if ($skip > 0) { $extraargs[] = '--skip=' . $skip; } } else { if ($count > 0) { $extraargs[] = '--max-count=' . ($count + $skip); } } $extraargs[] = $hash; if (count($args) > 0) { $endarg = array_search('--', $args); if ($endarg !== false) { array_splice($args, $endarg, 0, $extraargs); } else { $args = array_merge($args, $extraargs); } } else { $args = $extraargs; } $revlist = explode("\n", $this->exe->Execute($project->GetPath(), GIT_REV_LIST, $args)); if (!$revlist[count($revlist) - 1]) { /* the last newline creates a null entry */ array_splice($revlist, -1, 1); } if ($skip > 0 && !$canSkip) { if ($count > 0) { return array_slice($revlist, $skip, $count); } else { return array_slice($revlist, $skip); } } return $revlist; }
/** * PopulateProjects * * Populates the internal list of projects * * @access protected * @throws Exception if file cannot be read */ protected function PopulateProjects() { $projectRoot = GitPHP_Util::AddSlash(GitPHP_Config::GetInstance()->GetValue('projectroot')); $use_errors = libxml_use_internal_errors(true); $xml = simplexml_load_file($this->projectConfig); libxml_clear_errors(); libxml_use_internal_errors($use_errors); if (!$xml) { throw new Exception(sprintf('Could not load SCM manager config %1$s', $this->projectConfig)); } foreach ($xml->repositories->repository as $repository) { if ($repository->type != 'git') { GitPHP_Log::GetInstance()->Log(sprintf('%1$s is not a git project', $repository->name)); continue; } if ($repository->public != 'true') { GitPHP_Log::GetInstance()->Log(sprintf('%1$s is not public', $repository->name)); continue; } $projName = trim($repository->name); if (empty($projName)) { continue; } if (is_file($projectRoot . $projName . '/HEAD')) { try { $projObj = new GitPHP_Project($projectRoot, $projName); $projOwner = trim($repository->contact); if (!empty($projOwner)) { $projObj->SetOwner($projOwner); } $projDesc = trim($repository->description); if (!empty($projDesc)) { $projObj->SetDescription($projDesc); } $this->projects[$projName] = $projObj; } catch (Exception $e) { GitPHP_Log::GetInstance()->Log($e->getMessage()); } } else { GitPHP_Log::GetInstance()->Log(sprintf('%1$s is not a git project', $projName)); } } }
/** * PopulateProjects * * Populates the internal list of projects * * @access protected * @throws Exception if file cannot be read */ protected function PopulateProjects() { $projectRoot = GitPHP_Util::AddSlash(GitPHP_Config::GetInstance()->GetValue('projectroot')); foreach ($this->projectConfig as $cat => $plist) { if (is_array($plist)) { foreach ($plist as $pname => $ppath) { try { $projObj = new GitPHP_Project($projectRoot, $ppath); if ($cat != GITPHP_NO_CATEGORY) { $projObj->SetCategory($cat); } $this->projects[$ppath] = $projObj; } catch (Exception $e) { GitPHP_Log::GetInstance()->Log($e->getMessage()); } } } } }
/** * Loads the history data */ protected function LoadData() { $this->dataLoaded = true; $args = array(); $args[] = $this->hash; $args[] = '--no-merges'; $canSkip = true; if ($this->skip > 0) { $canSkip = $this->exe->CanSkip(); } if ($canSkip) { if ($this->limit > 0) { $args[] = '--max-count=' . $this->limit; } if ($this->skip > 0) { $args[] = '--skip=' . $this->skip; } } else { if ($this->limit > 0) { $args[] = '--max-count=' . ($this->limit + $this->skip); } } $args[] = '--'; $args[] = $this->path; $args[] = '|'; $args[] = $this->exe->GetBinary(); $args[] = '--git-dir=' . escapeshellarg($this->project->GetPath()); $args[] = GIT_DIFF_TREE; $args[] = '-r'; $args[] = '--stdin'; $args[] = '--'; $args[] = $this->path; $historylines = explode("\n", $this->exe->Execute($this->project->GetPath(), GIT_REV_LIST, $args)); $commitHash = null; foreach ($historylines as $line) { if (preg_match('/^([0-9a-fA-F]{40})/', $line, $regs)) { $commitHash = $regs[1]; } else { if ($commitHash) { try { $this->history[] = array('diffline' => $line, 'commithash' => $commitHash); } catch (Exception $e) { } $commitHash = null; } } } if ($this->skip > 0 && !$canSkip) { if ($this->limit > 0) { $this->history = array_slice($this->history, $this->skip, $this->limit); } else { $this->history = array_slice($this->history, $this->skip); } } }
/** * Constructor * * @param GitPHP_Project $project project * @param GitPHP_GitExe $exe executable * @param string $toHash to commit hash * @param string $fromHash from commit hash * @param boolean $renames whether to detect file renames */ public function __construct($project, $exe, $toHash, $fromHash = '', $renames = false) { if (!$project) { throw new Exception('Project is required'); } $this->project = $project; if (!$exe) { throw new Exception('Git executable is required'); } $this->exe = $exe; $toCommit = $project->GetCommit($toHash); $this->toHash = $toHash; if (empty($fromHash)) { $parent = $toCommit->GetParent(); if ($parent) { $this->fromHash = $parent->GetHash(); } } else { $this->fromHash = $fromHash; } $this->renames = $renames; }
/** * Loads the blame data */ private function LoadData() { $this->dataLoaded = true; $args = array(); $args[] = '-s'; $args[] = '-l'; $args[] = $this->commitHash; $args[] = '--'; $args[] = $this->path; $blamelines = explode("\n", $this->exe->Execute($this->project->GetPath(), GIT_BLAME, $args)); $lastcommit = ''; foreach ($blamelines as $line) { if (preg_match('/^([0-9a-fA-F]{40})(\\s+.+)?\\s+([0-9]+)\\)/', $line, $regs)) { if ($regs[1] != $lastcommit) { $this->blame[(int) $regs[3]] = $regs[1]; $lastcommit = $regs[1]; } } } }
/** * Gets a file diff * * @param string $fromHash source hash, can also be a diff-tree info line * @param string $toHash target hash, required if $fromHash is a hash * @return GitPHP_FileDiff file diff object */ public function GetFileDiff($fromHash, $toHash = '') { if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $fromHash) && !$this->compat) { $fullHash = $this->project->ExpandHash($fromHash); if ($fullHash == $fromHash) { throw new GitPHP_InvalidHashException($fromHash); } $fromHash = $fullHash; } if (!empty($toHash) && preg_match('/^[0-9A-Fa-f]{4,39}$/', $toHash) && !$this->compat) { $fullHash = $this->project->ExpandHash($toHash); if ($fullHash == $toHash) { throw new GitPHP_InvalidHashException($toHash); } $toHash = $fullHash; } $fileDiff = new GitPHP_FileDiff($this->project, $fromHash, $toHash); $fileDiff->SetCache($this->cache); return $fileDiff; }
/** * Finds loose hash files matching a given prefix * * @param string $prefix hash prefix * @return string[] array of hashes */ private function FindHashObjects($prefix) { $matches = array(); if (empty($prefix)) { return $matches; } $subdir = substr($prefix, 0, 2); $fulldir = $this->project->GetPath() . '/objects/' . $subdir; if (!is_dir($fulldir)) { return $matches; } $prefixlen = strlen($prefix); $dh = opendir($fulldir); if ($dh !== false) { while (($file = readdir($dh)) !== false) { $fullhash = $subdir . $file; if (substr_compare($fullhash, $prefix, 0, $prefixlen) === 0) { $matches[] = $fullhash; } } } return $matches; }
/** * Gets a project identifier for a project * * @param string|GitPHP_Project $value string or project * @return string identifier */ private static function GetProject($value) { if ($value instanceof GitPHP_Project) { return $value->GetProject(); } else { if (is_string($value)) { return $value; } } }
/** * AddProject * * Add project to collection * * @access private */ private function AddProject($projectPath) { try { $proj = new GitPHP_Project($this->projectDir, $projectPath); $category = trim(dirname($projectPath)); if (!(empty($category) || strpos($category, '.') === 0)) { $proj->SetCategory($category); } if (!GitPHP_Config::GetInstance()->GetValue('exportedonly', false) || $proj->GetDaemonEnabled()) { $this->projects[$projectPath] = $proj; } } catch (Exception $e) { GitPHP_Log::GetInstance()->Log($e->getMessage()); } }
/** * Applies override settings for a project * * @param GitPHP_Project $project the project object * @param array $projData project data array */ protected function ApplyProjectSettings($project, $projData) { if (!$project) { return; } if (isset($projData['category']) && is_string($projData['category'])) { $project->SetCategory($projData['category']); } if (isset($projData['owner']) && is_string($projData['owner'])) { $project->SetOwner($projData['owner']); } if (isset($projData['description']) && is_string($projData['description'])) { $project->SetDescription($projData['description']); } if (isset($projData['cloneurl']) && is_string($projData['cloneurl'])) { $project->SetCloneUrl($projData['cloneurl']); } if (isset($projData['pushurl']) && is_string($projData['pushurl'])) { $project->SetPushUrl($projData['pushurl']); } if (isset($projData['bugpattern']) && is_string($projData['bugpattern'])) { $project->SetBugPattern($projData['bugpattern']); } if (isset($projData['bugurl']) && is_string($projData['bugurl'])) { $project->SetBugUrl($projData['bugurl']); } if (isset($projData['compat'])) { $project->SetCompat($projData['compat']); } if (isset($projData['website']) && is_string($projData['website'])) { $project->SetWebsite($projData['website']); } if (!empty($projData['allowedusers'])) { $project->SetAllowedUsers($projData['allowedusers']); } }
/** * Loads a project * * @param string $proj project * @return GitPHP_Project project */ protected function LoadProject($proj) { try { $project = new GitPHP_Project($this->projectRoot, $proj); $category = trim(dirname($proj)); if (!(empty($category) || strpos($category, '.') === 0)) { $project->SetCategory($category); } if ($this->exportedOnly && !$project->GetDaemonEnabled()) { $this->Log('Project export disabled', $project->GetPath()); return null; } $this->ApplyGlobalConfig($project); $this->ApplyGitConfig($project); if ($this->projectSettings && isset($this->projectSettings[$proj])) { $this->ApplyProjectSettings($project, $this->projectSettings[$proj]); } $this->InjectProjectDependencies($project); return $project; } catch (Exception $e) { $this->Log('Project error', $e->getMessage()); } return null; }
/** * Compares two projects by age * * @param GitPHP_Project $a first project * @param GitPHP_Project $b second project * @return integer comparison result */ public static function CompareAge($a, $b) { $catCmp = strcmp($a->GetCategory(), $b->GetCategory()); if ($catCmp !== 0) { return $catCmp; } if ($a->GetAge() === $b->GetAge()) { return 0; } return $a->GetAge() < $b->GetAge() ? -1 : 1; }
public function testCompareAge() { $strategymock = $this->getMock('GitPHP_ProjectLoadStrategy_Interface'); $strategymock->expects($this->once())->method('LoadEpoch')->with($this->isInstanceOf('GitPHP_Project'))->will($this->returnValue('2')); $project = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepoexported.git', $strategymock); $strategymock2 = $this->getMock('GitPHP_ProjectLoadStrategy_Interface'); $strategymock2->expects($this->once())->method('LoadEpoch')->with($this->isInstanceOf('GitPHP_Project'))->will($this->returnValue('1')); $project2 = new GitPHP_Project(GITPHP_TEST_PROJECTROOT, 'testrepo.git', $strategymock2); $this->assertEquals(0, GitPHP_Project::CompareAge($project, $project)); $this->assertLessThan(0, GitPHP_Project::CompareAge($project, $project2)); $this->assertGreaterThan(0, GitPHP_Project::CompareAge($project2, $project)); $project->SetCategory('b'); $this->assertEquals(0, GitPHP_Project::CompareAge($project, $project)); $this->assertGreaterThan(0, GitPHP_Project::CompareAge($project, $project2)); $this->assertLessThan(0, GitPHP_Project::CompareAge($project2, $project)); $project2->SetCategory('a'); $this->assertEquals(0, GitPHP_Project::CompareAge($project, $project)); $this->assertGreaterThan(0, GitPHP_Project::CompareAge($project, $project2)); $this->assertLessThan(0, GitPHP_Project::CompareAge($project2, $project)); }
/** * Get diff data * * @param integer $context number of context lines * @param boolean $header true to include file header * @param string $file override file name * @return string diff data */ private function GetDiffData($context = 3, $header = true, $file = null) { $fromData = ''; $toData = ''; if (empty($this->status) || $this->status == 'M' || $this->status == 'D') { $fromBlob = $this->GetFromBlob(); $fromData = $fromBlob->GetData(false); } if (empty($this->status) || $this->status == 'M' || $this->status == 'A') { $toBlob = $this->GetToBlob(); $toData = $toBlob->GetData(false); } $output = ''; if ($header) { $output = '--- ' . $this->GetFromLabel($file) . "\n" . '+++ ' . $this->GetToLabel($file) . "\n"; } $diffOutput = false; $cacheKey = null; if ($this->cache) { $cacheKey = 'project|' . $this->project->GetProject() . '|diff|' . $context . '|' . $this->fromHash . '|' . $this->toHash; $diffOutput = $this->cache->Get($cacheKey); } if ($diffOutput === false) { if ($this->UseXDiff()) { $diffOutput = $this->GetXDiff($fromData, $toData, $context); } else { $diffOutput = $this->GetPhpDiff($fromData, $toData, $context); } if ($this->cache) { $this->cache->Set($cacheKey, $diffOutput); } } $output .= $diffOutput; return $output; }
/** * Abbreviate a hash * * @param GitPHP_Project $project project * @param string $hash hash to abbreviate * @return string abbreviated hash */ public function AbbreviateHash($project, $hash) { if (!$project) { return $hash; } if (!preg_match('/[0-9A-Fa-f]{40}/', $hash)) { return $hash; } $args = array(); $args[] = '-1'; $args[] = '--format=format:%h'; $args[] = $hash; $abbrevData = explode("\n", $this->exe->Execute($project->GetPath(), GIT_REV_LIST, $args)); if (empty($abbrevData[0])) { return $hash; } if (substr_compare(trim($abbrevData[0]), 'commit', 0, 6) !== 0) { return $hash; } if (empty($abbrevData[1])) { return $hash; } return trim($abbrevData[1]); }
/** * Abbreviate a hash * * @param GitPHP_Project $project project * @param string $hash hash to abbreviate * @return string abbreviated hash */ public function AbbreviateHash($project, $hash) { if (!$project) { return $hash; } if (!preg_match('/[0-9A-Fa-f]{40}/', $hash)) { return $hash; } $abbrevLen = GitPHP_ProjectLoad_Raw::HashAbbreviateLength; $projAbbrevLen = $project->GetAbbreviateLength(); if ($projAbbrevLen > 0) { $abbrevLen = max(4, min($projAbbrevLen, 40)); } $prefix = substr($hash, 0, $abbrevLen); if (!$project->GetUniqueAbbreviation()) { return $prefix; } return $this->objectLoader->EnsureUniqueHash($hash, $prefix); }