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:
parent
2bdcecc05d
commit
946ea3bffa
6 changed files with 109 additions and 16 deletions
2
resources/sql/autopatches/20150425.isclosed.sql
Normal file
2
resources/sql/autopatches/20150425.isclosed.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_repository.repository_refcursor
|
||||
ADD isClosed BOOL NOT NULL;
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue