1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-02-16 08:48:38 +01:00
phorge-phorge/src/applications/repository/daemon/PhabricatorGitGraphStream.php
epriestley 9a2c2505a0 Handle tag tags properly in discovery
Summary:
Fixes T11180. In Git, it's possible to tag a tag (????). When you do, we try to log the tag-object, which automatically resolves to the commit and fails.

Just skip these. If "A" points at "B" which points at "C", it's fine to ignore "A" and "B" since we'll get the same stuff when we process "C".

Test Plan:
  - Tagged a tag.
  - Pushed it.
  - Discovered it.
  - Before patch: got exception similar to the one in T11180.
  - After patch: got tag-tag skipped. Also got slightly better error messages.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11180

Differential Revision: https://secure.phabricator.com/D16149
2016-06-20 11:10:02 -07:00

105 lines
2.4 KiB
PHP

<?php
final class PhabricatorGitGraphStream
extends PhabricatorRepositoryGraphStream {
private $repository;
private $iterator;
private $startCommit;
private $parents = array();
private $dates = array();
public function __construct(
PhabricatorRepository $repository,
$start_commit = null) {
$this->repository = $repository;
$this->startCommit = $start_commit;
if ($start_commit !== null) {
$future = $repository->getLocalCommandFuture(
'log --format=%s %s --',
'%H%x01%P%x01%ct',
$start_commit);
} else {
$future = $repository->getLocalCommandFuture(
'log --format=%s --all --',
'%H%x01%P%x01%ct');
}
$this->iterator = new LinesOfALargeExecFuture($future);
$this->iterator->setDelimiter("\n");
$this->iterator->rewind();
}
public function getParents($commit) {
if (!isset($this->parents[$commit])) {
$this->parseUntil($commit);
}
$parents = $this->parents[$commit];
// NOTE: In Git, it is possible for a commit to list the same parent more
// than once. See T5226. Discard duplicate parents.
return array_unique($parents);
}
public function getCommitDate($commit) {
if (!isset($this->dates[$commit])) {
$this->parseUntil($commit);
}
return $this->dates[$commit];
}
private function parseUntil($commit) {
if ($this->isParsed($commit)) {
return;
}
$gitlog = $this->iterator;
while ($gitlog->valid()) {
$line = $gitlog->current();
$gitlog->next();
$line = trim($line);
if (!strlen($line)) {
break;
}
list($hash, $parents, $epoch) = explode("\1", $line);
if ($parents) {
$parents = explode(' ', $parents);
} else {
// First commit.
$parents = array();
}
$this->dates[$hash] = $epoch;
$this->parents[$hash] = $parents;
if ($this->isParsed($commit)) {
return;
}
}
if ($this->startCommit !== null) {
throw new Exception(
pht(
'Commit "%s" is not a reachable ancestor of "%s".',
$commit,
$this->startCommit));
} else {
throw new Exception(
pht(
'Commit "%s" is not a reachable ancestor of any ref.',
$commit));
}
}
private function isParsed($commit) {
return isset($this->dates[$commit]);
}
}