mirror of
https://we.phorge.it/source/phorge.git
synced 2025-02-16 08:48:38 +01:00
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
105 lines
2.4 KiB
PHP
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]);
|
|
}
|
|
|
|
}
|