1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-10 00:42:41 +01:00

Track closed branches in Mercurial

Summary: Ref T6160. Ref T7100. Mercurial branch heads can be closed; track this state so we can be smarter about it.

Test Plan: Closed a branch, run `repository update`, saw it close in the cursor table.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T6160, T7100

Differential Revision: https://secure.phabricator.com/D12550
This commit is contained in:
epriestley 2015-04-27 03:50:45 -07:00
parent 2bdcecc05d
commit 946ea3bffa
6 changed files with 109 additions and 16 deletions

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_repository.repository_refcursor
ADD isClosed BOOL NOT NULL;

View file

@ -75,7 +75,7 @@ final class DiffusionRefTableController extends DiffusionController {
$cached_hash = idx($cache, 'identifier');
if ($cached_hash !== null) {
$cache_hash = DiffusionView::linkCommit(
$cached_hash = DiffusionView::linkCommit(
$repository,
$cached_hash);
}

View file

@ -16,29 +16,57 @@ final class DiffusionLowLevelMercurialBranchesQuery
protected function executeQuery() {
$repository = $this->getRepository();
$specs = array();
if ($this->contains !== null) {
$spec = hgsprintf('(descendants(%s) and head())', $this->contains);
$specs['all'] = hgsprintf(
'(descendants(%s) and head())',
$this->contains);
$specs['open'] = hgsprintf(
'(descendants(%s) and head() and not closed())',
$this->contains);
} else {
$spec = hgsprintf('head()');
$specs['all'] = hgsprintf('head()');
$specs['open'] = hgsprintf('head() and not closed()');
}
list($stdout) = $repository->execxLocalCommand(
'log --template %s --rev %s',
'{node}\1{branch}\2',
$spec);
$futures = array();
foreach ($specs as $key => $spec) {
$futures[$key] = $repository->getLocalCommandFuture(
'log --template %s --rev %s',
'{node}\1{branch}\2',
$spec);
}
$branches = array();
$open = array();
foreach (new FutureIterator($futures) as $key => $future) {
list($stdout) = $future->resolvex();
$lines = explode("\2", $stdout);
$lines = array_filter($lines);
foreach ($lines as $line) {
list($node, $branch) = explode("\1", $line);
$branches[] = id(new DiffusionRepositoryRef())
->setShortName($branch)
->setCommitIdentifier($node);
$lines = explode("\2", $stdout);
$lines = array_filter($lines);
foreach ($lines as $line) {
list($node, $branch) = explode("\1", $line);
$id = $node.'/'.$branch;
if (empty($branches[$id])) {
$branches[$id] = id(new DiffusionRepositoryRef())
->setShortName($branch)
->setCommitIdentifier($node);
}
if ($key == 'open') {
$open[$id] = true;
}
}
}
return $branches;
foreach ($branches as $id => $branch) {
$branch->setRawFields(
array(
'closed' => (empty($open[$id])),
));
}
return array_values($branches);
}
}

View file

@ -19,6 +19,8 @@ final class PhabricatorRepositoryRefEngine
$repository = $this->getRepository();
$branches_may_close = false;
$vcs = $repository->getVersionControlSystem();
switch ($vcs) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
@ -31,6 +33,7 @@ final class PhabricatorRepositoryRefEngine
$branches = $this->loadMercurialBranchPositions($repository);
$bookmarks = $this->loadMercurialBookmarkPositions($repository);
$tags = array();
$branches_may_close = true;
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$branches = $this->loadGitBranchPositions($repository);
@ -87,6 +90,51 @@ final class PhabricatorRepositoryRefEngine
$this->newRefs = array();
$this->deadRefs = array();
}
if ($branches && $branches_may_close) {
$this->updateBranchStates($repository, $branches);
}
}
private function updateBranchStates(
PhabricatorRepository $repository,
array $branches) {
assert_instances_of($branches, 'DiffusionRepositoryRef');
$all_cursors = id(new PhabricatorRepositoryRefCursorQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withRepositoryPHIDs(array($repository->getPHID()))
->execute();
$state_map = array();
$type_branch = PhabricatorRepositoryRefCursor::TYPE_BRANCH;
foreach ($all_cursors as $cursor) {
if ($cursor->getRefType() !== $type_branch) {
continue;
}
$raw_name = $cursor->getRefNameRaw();
$hash = $cursor->getCommitIdentifier();
$state_map[$raw_name][$hash] = $cursor;
}
foreach ($branches as $branch) {
$cursor = idx($state_map, $branch->getShortName(), array());
$cursor = idx($cursor, $branch->getCommitIdentifier());
if (!$cursor) {
continue;
}
$fields = $branch->getRawFields();
$cursor_state = (bool)$cursor->getIsClosed();
$branch_state = (bool)idx($fields, 'closed');
if ($cursor_state != $branch_state) {
$cursor->setIsClosed((int)$branch_state)->save();
}
}
}
private function markRefNew(PhabricatorRepositoryRefCursor $cursor) {

View file

@ -544,9 +544,22 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
// trusted, Mercurial prints out a warning to stdout, twice, after Feb 2011.
//
// http://selenic.com/pipermail/mercurial-devel/2011-February/028541.html
//
// After Jan 2015, it may also fail to write to a revision branch cache.
$ignore = array(
'ignoring untrusted configuration option',
"couldn't write revision branch cache:",
);
foreach ($ignore as $key => $pattern) {
$ignore[$key] = preg_quote($pattern, '/');
}
$ignore = '('.implode('|', $ignore).')';
$lines = preg_split('/(?<=\n)/', $stdout);
$regex = '/ignoring untrusted configuration option .*\n$/';
$regex = '/'.$ignore.'.*\n$/';
foreach ($lines as $key => $line) {
$lines[$key] = preg_replace($regex, '', $line);

View file

@ -18,6 +18,7 @@ final class PhabricatorRepositoryRefCursor extends PhabricatorRepositoryDAO
protected $refNameRaw;
protected $refNameEncoding;
protected $commitIdentifier;
protected $isClosed = 0;
private $repository = self::ATTACHABLE;
@ -35,6 +36,7 @@ final class PhabricatorRepositoryRefCursor extends PhabricatorRepositoryDAO
// T6203/NULLABILITY
// This probably should not be nullable; refNameRaw is not nullable.
'refNameEncoding' => 'text16?',
'isClosed' => 'bool',
),
self::CONFIG_KEY_SCHEMA => array(
'key_cursor' => array(