Merge "expandshortcommitquery" and "stablecommitnamequery" into "resolverefs"

Summary:
Ref T1493. Diffusion has some garbagey behavior for things we can't resolve. Common cases are:

  - Looking at a branch that doesn't exist.
  - Looking at a repository with no branches.
  - Looking at a commit that doesn't exist.
  - Looking at an empty repository.

In these cases, we generally fatal unhelpfully. I want to untangle this mess.

This doesn't help much, but does clean things up a bit. We currently have two separate query paths, "stablecommitname" and "expandshortcommit". These are pretty much doing the same thing -- taking some ref like "master" or "default" or a tag name or part of a commit name, and turning it into a full commit name. Merge them into a single "resolverefs" method.

This simplifies the code a fair bit, and gives us better error messages. They still aren't great, but they're like this now:

  Ref "7498aec194ecf2d333e0e2baddd9d5cdf922d7f1" is ambiguous or does not exist.

...instead of just:

  ERR-INVALID-COMMIT

Test Plan: Looked at Git, Mercurial and Subversion repositories that were empty and non-empty. Looked at branches/heads. Tried to look at invalid commits. Looked at tags. All of this still works, and some behaviors are a bit better than they used to be.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T1493

Differential Revision: https://secure.phabricator.com/D7484
This commit is contained in:
epriestley 2013-11-04 14:13:07 -08:00
parent 8f3ae81143
commit 4f20530856
16 changed files with 308 additions and 421 deletions

View file

@ -151,7 +151,6 @@ phutil_register_library_map(array(
'ConduitAPI_diffusion_createcomment_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_createcomment_Method.php',
'ConduitAPI_diffusion_diffquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_diffquery_Method.php',
'ConduitAPI_diffusion_existsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_existsquery_Method.php',
'ConduitAPI_diffusion_expandshortcommitquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_expandshortcommitquery_Method.php',
'ConduitAPI_diffusion_filecontentquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_filecontentquery_Method.php',
'ConduitAPI_diffusion_findsymbols_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_findsymbols_Method.php',
'ConduitAPI_diffusion_getcommits_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_getcommits_Method.php',
@ -164,8 +163,8 @@ phutil_register_library_map(array(
'ConduitAPI_diffusion_rawdiffquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_rawdiffquery_Method.php',
'ConduitAPI_diffusion_readmequery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_readmequery_Method.php',
'ConduitAPI_diffusion_refsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_refsquery_Method.php',
'ConduitAPI_diffusion_resolverefs_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_resolverefs_Method.php',
'ConduitAPI_diffusion_searchquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_searchquery_Method.php',
'ConduitAPI_diffusion_stablecommitnamequery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_stablecommitnamequery_Method.php',
'ConduitAPI_diffusion_tagsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_tagsquery_Method.php',
'ConduitAPI_feed_Method' => 'applications/feed/conduit/ConduitAPI_feed_Method.php',
'ConduitAPI_feed_publish_Method' => 'applications/feed/conduit/ConduitAPI_feed_publish_Method.php',
@ -472,20 +471,16 @@ phutil_register_library_map(array(
'DiffusionDiffController' => 'applications/diffusion/controller/DiffusionDiffController.php',
'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php',
'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php',
'DiffusionExpandCommitQueryException' => 'applications/diffusion/exception/DiffusionExpandCommitQueryException.php',
'DiffusionExpandShortNameQuery' => 'applications/diffusion/query/expandshortname/DiffusionExpandShortNameQuery.php',
'DiffusionExternalController' => 'applications/diffusion/controller/DiffusionExternalController.php',
'DiffusionFileContent' => 'applications/diffusion/data/DiffusionFileContent.php',
'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionFileContentQuery.php',
'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php',
'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php',
'DiffusionGitCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionGitCommitParentsQuery.php',
'DiffusionGitExpandShortNameQuery' => 'applications/diffusion/query/expandshortname/DiffusionGitExpandShortNameQuery.php',
'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php',
'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php',
'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php',
'DiffusionGitResponse' => 'applications/diffusion/response/DiffusionGitResponse.php',
'DiffusionGitStableCommitNameQuery' => 'applications/diffusion/query/stablecommitname/DiffusionGitStableCommitNameQuery.php',
'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php',
'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php',
'DiffusionHovercardEventListener' => 'applications/diffusion/events/DiffusionHovercardEventListener.php',
@ -498,12 +493,11 @@ phutil_register_library_map(array(
'DiffusionLowLevelGitRefQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelGitRefQuery.php',
'DiffusionLowLevelMercurialBranchesQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelMercurialBranchesQuery.php',
'DiffusionLowLevelQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelQuery.php',
'DiffusionLowLevelResolveRefsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php',
'DiffusionMercurialCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionMercurialCommitParentsQuery.php',
'DiffusionMercurialExpandShortNameQuery' => 'applications/diffusion/query/expandshortname/DiffusionMercurialExpandShortNameQuery.php',
'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php',
'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php',
'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php',
'DiffusionMercurialStableCommitNameQuery' => 'applications/diffusion/query/stablecommitname/DiffusionMercurialStableCommitNameQuery.php',
'DiffusionPathChange' => 'applications/diffusion/data/DiffusionPathChange.php',
'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php',
'DiffusionPathCompleteController' => 'applications/diffusion/controller/DiffusionPathCompleteController.php',
@ -542,12 +536,10 @@ phutil_register_library_map(array(
'DiffusionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSSHWorkflow.php',
'DiffusionSetPasswordPanel' => 'applications/diffusion/panel/DiffusionSetPasswordPanel.php',
'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php',
'DiffusionStableCommitNameQuery' => 'applications/diffusion/query/stablecommitname/DiffusionStableCommitNameQuery.php',
'DiffusionSvnCommitParentsQuery' => 'applications/diffusion/query/parents/DiffusionSvnCommitParentsQuery.php',
'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionSvnFileContentQuery.php',
'DiffusionSvnRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionSvnRawDiffQuery.php',
'DiffusionSvnRequest' => 'applications/diffusion/request/DiffusionSvnRequest.php',
'DiffusionSvnStableCommitNameQuery' => 'applications/diffusion/query/stablecommitname/DiffusionSvnStableCommitNameQuery.php',
'DiffusionSymbolController' => 'applications/diffusion/controller/DiffusionSymbolController.php',
'DiffusionSymbolQuery' => 'applications/diffusion/query/DiffusionSymbolQuery.php',
'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php',
@ -2366,7 +2358,6 @@ phutil_register_library_map(array(
'ConduitAPI_diffusion_createcomment_Method' => 'ConduitAPI_diffusion_Method',
'ConduitAPI_diffusion_diffquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_existsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_expandshortcommitquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_filecontentquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_findsymbols_Method' => 'ConduitAPI_diffusion_Method',
'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPI_diffusion_Method',
@ -2379,8 +2370,8 @@ phutil_register_library_map(array(
'ConduitAPI_diffusion_rawdiffquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_readmequery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_refsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_resolverefs_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_searchquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_stablecommitnamequery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_diffusion_tagsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method',
'ConduitAPI_feed_Method' => 'ConduitAPIMethod',
'ConduitAPI_feed_publish_Method' => 'ConduitAPI_feed_Method',
@ -2681,18 +2672,14 @@ phutil_register_library_map(array(
'DiffusionDiffController' => 'DiffusionController',
'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher',
'DiffusionEmptyResultView' => 'DiffusionView',
'DiffusionExpandCommitQueryException' => 'Exception',
'DiffusionExpandShortNameQuery' => 'DiffusionQuery',
'DiffusionExternalController' => 'DiffusionController',
'DiffusionFileContentQuery' => 'DiffusionQuery',
'DiffusionGitBranchTestCase' => 'PhabricatorTestCase',
'DiffusionGitCommitParentsQuery' => 'DiffusionCommitParentsQuery',
'DiffusionGitExpandShortNameQuery' => 'DiffusionExpandShortNameQuery',
'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery',
'DiffusionGitRequest' => 'DiffusionRequest',
'DiffusionGitResponse' => 'AphrontResponse',
'DiffusionGitStableCommitNameQuery' => 'DiffusionStableCommitNameQuery',
'DiffusionHistoryController' => 'DiffusionController',
'DiffusionHistoryTableView' => 'DiffusionView',
'DiffusionHovercardEventListener' => 'PhabricatorEventListener',
@ -2704,12 +2691,11 @@ phutil_register_library_map(array(
'DiffusionLowLevelGitRefQuery' => 'DiffusionLowLevelQuery',
'DiffusionLowLevelMercurialBranchesQuery' => 'DiffusionLowLevelQuery',
'DiffusionLowLevelQuery' => 'Phobject',
'DiffusionLowLevelResolveRefsQuery' => 'DiffusionLowLevelQuery',
'DiffusionMercurialCommitParentsQuery' => 'DiffusionCommitParentsQuery',
'DiffusionMercurialExpandShortNameQuery' => 'DiffusionExpandShortNameQuery',
'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery',
'DiffusionMercurialRequest' => 'DiffusionRequest',
'DiffusionMercurialStableCommitNameQuery' => 'DiffusionStableCommitNameQuery',
'DiffusionPathCompleteController' => 'DiffusionController',
'DiffusionPathQueryTestCase' => 'PhabricatorTestCase',
'DiffusionPathValidateController' => 'DiffusionController',
@ -2743,12 +2729,10 @@ phutil_register_library_map(array(
'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow',
'DiffusionSetPasswordPanel' => 'PhabricatorSettingsPanel',
'DiffusionSetupException' => 'AphrontUsageException',
'DiffusionStableCommitNameQuery' => 'DiffusionQuery',
'DiffusionSvnCommitParentsQuery' => 'DiffusionCommitParentsQuery',
'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery',
'DiffusionSvnRawDiffQuery' => 'DiffusionRawDiffQuery',
'DiffusionSvnRequest' => 'DiffusionRequest',
'DiffusionSvnStableCommitNameQuery' => 'DiffusionStableCommitNameQuery',
'DiffusionSymbolController' => 'DiffusionController',
'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery',
'DiffusionTagListController' => 'DiffusionController',

View file

@ -198,7 +198,7 @@ final class ConduitAPI_diffusion_browsequery_Method
list($entire_manifest) = $repository->execxLocalCommand(
'manifest --rev %s',
$commit);
hgsprintf('%s', $commit));
$entire_manifest = explode("\n", $entire_manifest);
$results = array();

View file

@ -1,70 +0,0 @@
<?php
/**
* @group conduit
*/
final class ConduitAPI_diffusion_expandshortcommitquery_Method
extends ConduitAPI_diffusion_abstractquery_Method {
public function __construct() {
$this->setShouldCreateDiffusionRequest(false);
}
public function getMethodDescription() {
return
'Expands a short commit name to its full glory.';
}
public function defineReturnType() {
return 'array';
}
protected function defineCustomParamTypes() {
return array(
'commit' => 'required string',
);
}
protected function defineCustomErrorTypes() {
return array(
'ERR-MISSING-COMMIT' => pht(
'Bad commit.'),
'ERR-INVALID-COMMIT' => pht(
'Invalid object name.'),
'ERR-UNPARSEABLE-OUTPUT' => pht(
'Unparseable output from cat-file.')
);
}
protected function getGitResult(ConduitAPIRequest $request) {
return $this->getGitOrMercurialResult($request);
}
protected function getMercurialResult(ConduitAPIRequest $request) {
return $this->getGitOrMercurialResult($request);
}
private function getGitOrMercurialResult(ConduitAPIRequest $request) {
$repository = $this->getRepository($request);
$query = DiffusionExpandShortNameQuery::newFromRepository($repository);
$query->setCommit($request->getValue('commit'));
try {
$result = $query->expand();
return $result;
} catch (DiffusionExpandCommitQueryException $e) {
switch ($e->getStatusCode()) {
case DiffusionExpandCommitQueryException::CODE_INVALID:
throw id(new ConduitException('ERR-INVALID-COMMIT'))
->setErrorDescription($e->getMessage());
break;
case DiffusionExpandCommitQueryException::CODE_MISSING:
throw id(new ConduitException('ERR-MISSING-COMMIT'))
->setErrorDescription($e->getMessage());
break;
case DiffusionExpandCommitQueryException::CODE_UNPARSEABLE:
throw id(new ConduitException('ERR-UNPARSEABLE-OUTPUT'))
->setErrorDescription($e->getMessage());
break;
}
}
}
}

View file

@ -0,0 +1,29 @@
<?php
final class ConduitAPI_diffusion_resolverefs_Method
extends ConduitAPI_diffusion_abstractquery_Method {
public function getMethodDescription() {
return pht('Resolve references into stable, canonical identifiers.');
}
public function defineReturnType() {
return 'dict<string, list<dict<string, wild>>>';
}
protected function defineCustomParamTypes() {
return array(
'refs' => 'required list<string>',
);
}
protected function getResult(ConduitAPIRequest $request) {
$refs = $request->getValue('refs');
return id(new DiffusionLowLevelResolveRefsQuery())
->setRepository($this->getDiffusionRequest()->getRepository())
->withRefs($refs)
->execute();
}
}

View file

@ -1,35 +0,0 @@
<?php
/**
* @group conduit
*/
final class ConduitAPI_diffusion_stablecommitnamequery_Method
extends ConduitAPI_diffusion_abstractquery_Method {
public function __construct() {
$this->setShouldCreateDiffusionRequest(false);
}
public function getMethodDescription() {
return
'Identifies the latest commit in a repository. Repositories with '.
'branch support must specify which branch to look at.';
}
public function defineReturnType() {
return 'string';
}
protected function defineCustomParamTypes() {
return array(
'branch' => 'required string',
);
}
protected function getResult(ConduitAPIRequest $request) {
$repository = $this->getRepository($request);
$query = DiffusionStableCommitNameQuery::newFromRepository($repository);
$query->setBranch($request->getValue('branch'));
return $query->load();
}
}

View file

@ -1,21 +0,0 @@
<?php
final class DiffusionExpandCommitQueryException extends Exception {
const CODE_UNPARSEABLE = 'unparseable';
const CODE_MISSING = 'missing';
const CODE_INVALID = 'invalid';
private $statusCode;
public function getStatusCode() {
return $this->statusCode;
}
public function __construct($status_code /* ... */) {
$args = func_get_args();
$this->statusCode = $args[0];
$args = array_slice($args, 1);
call_user_func_array(array('parent', '__construct'), $args);
}
}

View file

@ -1,51 +0,0 @@
<?php
abstract class DiffusionExpandShortNameQuery extends DiffusionQuery {
private $commit;
private $commitType = 'commit';
private $tagContent;
private $repository;
public function setCommit($commit) {
$this->commit = $commit;
}
public function getCommit() {
return $this->commit;
}
public function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function getRepository() {
return $this->repository;
}
protected function setCommitType($type) {
$this->commitType = $type;
return $this;
}
protected function setTagContent($content) {
$this->tagContent = $content;
return $this;
}
final public static function newFromRepository(
PhabricatorRepository $repository) {
$obj = parent::initQueryObject(__CLASS__, $repository);
$obj->setRepository($repository);
return $obj;
}
final public function expand() {
$this->executeQuery();
return array(
'commit' => $this->commit,
'commitType' => $this->commitType,
'tagContent' => $this->tagContent);
}
}

View file

@ -1,52 +0,0 @@
<?php
final class DiffusionGitExpandShortNameQuery
extends DiffusionExpandShortNameQuery {
protected function executeQuery() {
$repository = $this->getRepository();
$commit = $this->getCommit();
$future = $repository->getLocalCommandFuture(
'cat-file --batch');
$future->write($commit);
list($stdout) = $future->resolvex();
list($hash, $type) = explode(' ', $stdout);
if ($type == 'missing') {
throw new DiffusionExpandCommitQueryException(
DiffusionExpandCommitQueryException::CODE_MISSING,
"Bad commit '{$commit}'.");
}
switch ($type) {
case 'tag':
$this->setCommitType('tag');
$matches = null;
$ok = preg_match(
'/^object ([a-f0-9]+)$.*?\n\n(.*)$/sm',
$stdout,
$matches);
if (!$ok) {
throw new DiffusionExpandCommitQueryException(
DiffusionExpandCommitQueryException::CODE_UNPARSEABLE,
"Unparseable output from cat-file: {$stdout}");
}
$hash = $matches[1];
$this->setTagContent(trim($matches[2]));
break;
case 'commit':
break;
default:
throw new DiffusionExpandCommitQueryException(
DiffusionExpandCommitQueryException::CODE_INVALID,
"The reference '{$commit}' does not name a valid ".
'commit or a tag in this repository.');
break;
}
$this->setCommit($hash);
}
}

View file

@ -1,23 +0,0 @@
<?php
final class DiffusionMercurialExpandShortNameQuery
extends DiffusionExpandShortNameQuery {
protected function executeQuery() {
$repository = $this->getRepository();
$commit = $this->getCommit();
list($full_hash) = $repository->execxLocalCommand(
'log --template=%s --rev %s',
'{node}',
$commit);
$full_hash = explode("\n", trim($full_hash));
// TODO: Show "multiple matching commits" if count is larger than 1. For
// now, pick the first one.
$this->setCommit(head($full_hash));
}
}

View file

@ -16,6 +16,10 @@ abstract class DiffusionLowLevelQuery extends Phobject {
}
public function execute() {
if (!$this->getRepository()) {
throw new Exception("Call setRepository() before execute()!");
}
return $this->executeQuery();
}

View file

@ -0,0 +1,225 @@
<?php
/**
* Resolves references (like short commit names, branch names, tag names, etc.)
* into canonical, stable commit identifiers. This query works for all
* repository types.
*/
final class DiffusionLowLevelResolveRefsQuery
extends DiffusionLowLevelQuery {
private $refs;
public function withRefs(array $refs) {
$this->refs = $refs;
return $this;
}
public function executeQuery() {
if (!$this->refs) {
return array();
}
switch ($this->getRepository()->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
$result = $this->resolveGitRefs();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$result = $this->resolveMercurialRefs();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$result = $this->resolveSubversionRefs();
break;
default:
throw new Exception("Unsupported repository type!");
}
return $result;
}
private function resolveGitRefs() {
$repository = $this->getRepository();
$future = $repository->getLocalCommandFuture('cat-file --batch-check');
$future->write(implode("\n", $this->refs));
list($stdout) = $future->resolvex();
$lines = explode("\n", rtrim($stdout, "\n"));
if (count($lines) !== count($this->refs)) {
throw new Exception("Unexpected line count from `git cat-file`!");
}
$hits = array();
$tags = array();
$lines = array_combine($this->refs, $lines);
foreach ($lines as $ref => $line) {
$parts = explode(' ', $line);
if (count($parts) < 2) {
throw new Exception("Failed to parse `git cat-file` output: {$line}");
}
list($identifier, $type) = $parts;
if ($type == 'missing') {
// This is either an ambiguous reference which resolves to several
// objects, or an invalid reference. For now, always treat it as
// invalid. It would be nice to resolve all possibilities for
// ambiguous references at some point, although the strategy for doing
// so isn't clear to me.
continue;
}
switch ($type) {
case 'commit':
break;
case 'tag':
$tags[] = $identifier;
break;
default:
throw new Exception(
"Unexpected object type from `git cat-file`: {$line}");
}
$hits[] = array(
'ref' => $ref,
'type' => $type,
'identifier' => $identifier,
);
}
$tag_map = array();
if ($tags) {
// If some of the refs were tags, just load every tag in order to figure
// out which commits they map to. This might be somewhat inefficient in
// repositories with a huge number of tags.
$tag_refs = id(new DiffusionLowLevelGitRefQuery())
->setRepository($repository)
->withIsTag(true)
->executeQuery();
foreach ($tag_refs as $tag_ref) {
$tag_map[$tag_ref->getShortName()] = $tag_ref->getCommitIdentifier();
}
}
$results = array();
foreach ($hits as $hit) {
$type = $hit['type'];
$ref = $hit['ref'];
$alternate = null;
if ($type == 'tag') {
$alternate = $identifier;
$identifier = idx($tag_map, $ref);
if (!$identifier) {
throw new Exception("Failed to look up tag '{$ref}'!");
}
}
$result = array(
'type' => $type,
'identifier' => $identifier,
);
if ($alternate !== null) {
$result['alternate'] = $alternate;
}
$results[$ref][] = $result;
}
return $results;
}
private function resolveMercurialRefs() {
$repository = $this->getRepository();
$futures = array();
foreach ($this->refs as $ref) {
// TODO: There was a note about `--rev 'a b'` not working for branches
// with spaces in their names in older code, but I suspect this was
// misidentified and resulted from the branch name being interpeted as
// a revset. Use hgsprintf() to avoid that. If this doesn't break for a
// bit, remove this comment. Otherwise, consider `-b %s --limit 1`.
$futures[$ref] = $repository->getLocalCommandFuture(
'log --template=%s --rev %s',
'{node}',
hgsprintf('%s', $ref));
}
$results = array();
foreach (Futures($futures) as $ref => $future) {
try {
list($stdout) = $future->resolvex();
} catch (CommandException $ex) {
if (preg_match('/ambiguous identifier/', $ex->getStdErr())) {
// This indicates that the ref ambiguously matched several things.
// Eventually, it would be nice to return all of them, but it is
// unclear how to best do that. For now, treat it as a miss instead.
continue;
}
throw $ex;
}
// It doesn't look like we can figure out the type (commit/branch/rev)
// from this output very easily. For now, just call everything a commit.
$type = 'commit';
$results[$ref][] = array(
'type' => $type,
'identifier' => trim($stdout),
);
}
return $results;
}
private function resolveSubversionRefs() {
$repository = $this->getRepository();
$max_commit = id(new PhabricatorRepositoryCommit())
->loadOneWhere(
'repositoryID = %d ORDER BY epoch DESC, id DESC LIMIT 1',
$repository->getID());
if (!$max_commit) {
// This repository is empty or hasn't parsed yet, so none of the refs are
// going to resolve.
return array();
}
$max_commit_id = (int)$max_commit->getCommitIdentifier();
$results = array();
foreach ($this->refs as $ref) {
if ($ref == 'HEAD') {
// Resolve "HEAD" to mean "the most recent commit".
$results[$ref][] = array(
'type' => 'commit',
'identifier' => $max_commit_id,
);
continue;
}
if (!preg_match('/^\d+$/', $ref)) {
// This ref is non-numeric, so it doesn't resolve to anything.
continue;
}
// Resolve other commits if we can deduce their existence.
// TODO: When we import only part of a repository, we won't necessarily
// have all of the smaller commits. Should we fail to resolve them here
// for repositories with a subpath? It might let us simplify other things
// elsewhere.
if ((int)$ref <= $max_commit_id) {
$results[$ref][] = array(
'type' => 'commit',
'identifier' => (int)$ref,
);
}
}
return $results;
}
}

View file

@ -1,24 +0,0 @@
<?php
final class DiffusionGitStableCommitNameQuery
extends DiffusionStableCommitNameQuery {
protected function executeQuery() {
$repository = $this->getRepository();
$branch = $this->getBranch();
if ($repository->isWorkingCopyBare()) {
list($stdout) = $repository->execxLocalCommand(
'rev-parse --verify %s',
$branch);
} else {
list($stdout) = $repository->execxLocalCommand(
'rev-parse --verify %s/%s',
DiffusionBranchInformation::DEFAULT_GIT_REMOTE,
$branch);
}
$commit = trim($stdout);
return substr($commit, 0, 16);
}
}

View file

@ -1,30 +0,0 @@
<?php
final class DiffusionMercurialStableCommitNameQuery
extends DiffusionStableCommitNameQuery {
protected function executeQuery() {
$repository = $this->getRepository();
// NOTE: For branches with spaces in their name like "a b", this
// does not work properly:
//
// $ hg log --rev 'a b'
//
// We can use revsets instead:
//
// $ hg log --rev branch('a b')
//
// ...but they require a somewhat newer version of Mercurial. Instead,
// use "-b" flag with limit 1 for greatest compatibility across
// versions.
list($stable_commit_name) = $repository->execxLocalCommand(
'log --template=%s -b %s --limit 1',
'{node}',
$this->getBranch());
return $stable_commit_name;
}
}

View file

@ -1,35 +0,0 @@
<?php
abstract class DiffusionStableCommitNameQuery extends DiffusionQuery {
private $branch;
private $repository;
public function setBranch($branch) {
$this->branch = $branch;
return $this;
}
public function getBranch() {
return $this->branch;
}
public function setRepository(PhabricatorRepository $repository) {
$this->repository = $repository;
return $this;
}
public function getRepository() {
return $this->repository;
}
final public static function newFromRepository(
PhabricatorRepository $repository) {
$obj = parent::initQueryObject(__CLASS__, $repository);
$obj->setRepository($repository);
return $obj;
}
final public function load() {
return $this->executeQuery();
}
}

View file

@ -1,23 +0,0 @@
<?php
final class DiffusionSvnStableCommitNameQuery
extends DiffusionStableCommitNameQuery {
protected function executeQuery() {
$repository = $this->getRepository();
$commit = id(new PhabricatorRepositoryCommit())
->loadOneWhere(
'repositoryID = %d ORDER BY epoch DESC LIMIT 1',
$repository->getID());
if ($commit) {
$stable_commit_name = $commit->getCommitIdentifier();
} else {
// For new repositories, we may not have parsed any commits yet. Call
// the stable commit "1" and avoid fataling.
$stable_commit_name = 1;
}
return $stable_commit_name;
}
}

View file

@ -18,7 +18,6 @@ abstract class DiffusionRequest {
protected $symbolicCommit;
protected $commit;
protected $commitType = 'commit';
protected $tagContent;
protected $branch;
protected $lint;
@ -263,10 +262,6 @@ abstract class DiffusionRequest {
$this->getArcanistBranch());
}
public function getTagContent() {
return $this->tagContent;
}
public function loadCommit() {
if (empty($this->repositoryCommit)) {
$repository = $this->getRepository();
@ -624,26 +619,17 @@ abstract class DiffusionRequest {
}
final protected function expandCommitName() {
if ($this->shouldInitFromConduit()) {
$commit_data = DiffusionQuery::callConduitWithDiffusionRequest(
$this->getUser(),
$this,
'diffusion.expandshortcommitquery',
array(
'commit' => $this->commit
));
} else {
$repository = $this->getRepository();
$this->validateWorkingCopy($repository->getLocalPath());
$query = DiffusionExpandShortNameQuery::newFromRepository(
$repository);
$query->setCommit($this->commit);
$commit_data = $query->expand();
$results = $this->resolveRefs(array($this->commit));
$matches = idx($results, $this->commit, array());
if (count($results) !== 1) {
throw new Exception(
pht('Ref "%s" is ambiguous or does not exist.', $this->commit));
}
$this->commit = $commit_data['commit'];
$this->commitType = $commit_data['commitType'];
$this->tagContent = $commit_data['tagContent'];
$match = head($matches);
$this->commit = $match['identifier'];
$this->commitType = $match['type'];
}
public function getCommitType() {
@ -653,20 +639,43 @@ abstract class DiffusionRequest {
private function queryStableCommitName() {
if ($this->commit) {
$this->stableCommitName = $this->commit;
} else if ($this->shouldInitFromConduit()) {
$this->stableCommitName = DiffusionQuery::callConduitWithDiffusionRequest(
$this->getUser(),
$this,
'diffusion.stablecommitnamequery',
array(
'branch' => $this->getBranch()
));
} else {
$query = DiffusionStableCommitNameQuery::newFromRepository(
$this->getRepository());
$query->setBranch($this->getBranch());
$this->stableCommitName = $query->load();
return $this->stableCommitName;
}
if ($this->getSupportsBranches()) {
$branch = $this->getBranch();
} else {
$branch = 'HEAD';
}
$results = $this->resolveRefs(array($branch));
$matches = idx($results, $branch, array());
if (count($matches) !== 1) {
throw new Exception(
pht('Ref "%s" is ambiguous or does not exist.', $branch));
}
$this->stableCommitName = idx(head($matches), 'identifier');
return $this->stableCommitName;
}
private function resolveRefs(array $refs) {
if ($this->shouldInitFromConduit()) {
return DiffusionQuery::callConduitWithDiffusionRequest(
$this->getUser(),
$this,
'diffusion.resolverefs',
array(
'refs' => $refs,
));
} else {
return id(new DiffusionLowLevelResolveRefsQuery())
->setRepository($this->getRepository())
->withRefs($refs)
->execute();
}
}
}