1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-12-01 19:22:41 +01:00

Implement a revision resolver for arc browse <commit>

Summary: Ref T10895. This allows `arc browse <commit name>` to resolve to a revision, if an associated open revision exists.

Test Plan: Ran `arc browse` with various arguments.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T10895

Differential Revision: https://secure.phabricator.com/D16933
This commit is contained in:
epriestley 2016-11-23 10:16:31 -08:00
parent d00de495bc
commit 84857e4890
8 changed files with 166 additions and 26 deletions

View file

@ -47,6 +47,7 @@ phutil_register_library_map(array(
'ArcanistBrowseObjectNameURIHardpointLoader' => 'browse/loader/ArcanistBrowseObjectNameURIHardpointLoader.php', 'ArcanistBrowseObjectNameURIHardpointLoader' => 'browse/loader/ArcanistBrowseObjectNameURIHardpointLoader.php',
'ArcanistBrowsePathURIHardpointLoader' => 'browse/loader/ArcanistBrowsePathURIHardpointLoader.php', 'ArcanistBrowsePathURIHardpointLoader' => 'browse/loader/ArcanistBrowsePathURIHardpointLoader.php',
'ArcanistBrowseRef' => 'browse/ref/ArcanistBrowseRef.php', 'ArcanistBrowseRef' => 'browse/ref/ArcanistBrowseRef.php',
'ArcanistBrowseRevisionURIHardpointLoader' => 'browse/loader/ArcanistBrowseRevisionURIHardpointLoader.php',
'ArcanistBrowseURIHardpointLoader' => 'browse/loader/ArcanistBrowseURIHardpointLoader.php', 'ArcanistBrowseURIHardpointLoader' => 'browse/loader/ArcanistBrowseURIHardpointLoader.php',
'ArcanistBrowseURIRef' => 'browse/ref/ArcanistBrowseURIRef.php', 'ArcanistBrowseURIRef' => 'browse/ref/ArcanistBrowseURIRef.php',
'ArcanistBrowseWorkflow' => 'browse/workflow/ArcanistBrowseWorkflow.php', 'ArcanistBrowseWorkflow' => 'browse/workflow/ArcanistBrowseWorkflow.php',
@ -168,6 +169,7 @@ phutil_register_library_map(array(
'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php', 'ArcanistGeneratedLinterTestCase' => 'lint/linter/__tests__/ArcanistGeneratedLinterTestCase.php',
'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php', 'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php',
'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php', 'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php',
'ArcanistGitCommitMessageHardpointLoader' => 'loader/ArcanistGitCommitMessageHardpointLoader.php',
'ArcanistGitHardpointLoader' => 'loader/ArcanistGitHardpointLoader.php', 'ArcanistGitHardpointLoader' => 'loader/ArcanistGitHardpointLoader.php',
'ArcanistGitLandEngine' => 'land/ArcanistGitLandEngine.php', 'ArcanistGitLandEngine' => 'land/ArcanistGitLandEngine.php',
'ArcanistGitRevisionHardpointLoader' => 'loader/ArcanistGitRevisionHardpointLoader.php', 'ArcanistGitRevisionHardpointLoader' => 'loader/ArcanistGitRevisionHardpointLoader.php',
@ -487,6 +489,7 @@ phutil_register_library_map(array(
'ArcanistBrowseObjectNameURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader', 'ArcanistBrowseObjectNameURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
'ArcanistBrowsePathURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader', 'ArcanistBrowsePathURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
'ArcanistBrowseRef' => 'ArcanistRef', 'ArcanistBrowseRef' => 'ArcanistRef',
'ArcanistBrowseRevisionURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
'ArcanistBrowseURIHardpointLoader' => 'ArcanistHardpointLoader', 'ArcanistBrowseURIHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistBrowseURIRef' => 'ArcanistRef', 'ArcanistBrowseURIRef' => 'ArcanistRef',
'ArcanistBrowseWorkflow' => 'ArcanistWorkflow', 'ArcanistBrowseWorkflow' => 'ArcanistWorkflow',
@ -608,6 +611,7 @@ phutil_register_library_map(array(
'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase', 'ArcanistGeneratedLinterTestCase' => 'ArcanistLinterTestCase',
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow', 'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
'ArcanistGitAPI' => 'ArcanistRepositoryAPI', 'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
'ArcanistGitCommitMessageHardpointLoader' => 'ArcanistGitHardpointLoader',
'ArcanistGitHardpointLoader' => 'ArcanistHardpointLoader', 'ArcanistGitHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistGitLandEngine' => 'ArcanistLandEngine', 'ArcanistGitLandEngine' => 'ArcanistLandEngine',
'ArcanistGitRevisionHardpointLoader' => 'ArcanistGitHardpointLoader', 'ArcanistGitRevisionHardpointLoader' => 'ArcanistGitHardpointLoader',

View file

@ -33,9 +33,6 @@ final class ArcanistBrowseCommitHardpointLoader
$commit_map = array(); $commit_map = array();
foreach ($refs as $key => $ref) { foreach ($refs as $key => $ref) {
$is_commit = $ref->hasType(
ArcanistBrowseCommitURIHardpointLoader::BROWSETYPE);
$token = $ref->getToken(); $token = $ref->getToken();
if ($token === '.') { if ($token === '.') {
@ -44,14 +41,16 @@ final class ArcanistBrowseCommitHardpointLoader
continue; continue;
} }
// Always resolve the empty token; top-level loaders filter out
// irrelevant tokens before this stage.
if ($token === null) { if ($token === null) {
if ($is_commit) {
$token = $api->getHeadCommit(); $token = $api->getHeadCommit();
} else {
continue;
}
} }
// TODO: We should pull a full commit ref out of the API as soon as it
// is able to provide them. In particular, we currently miss Git tree
// hashes which reduces the accuracy of lookups.
try { try {
$commit = $api->getCanonicalRevisionName($token); $commit = $api->getCanonicalRevisionName($token);
if ($commit) { if ($commit) {

View file

@ -47,7 +47,6 @@ final class ArcanistBrowseCommitURIHardpointLoader
} }
$refs = $this->getRefsWithSupportedTypes($refs); $refs = $this->getRefsWithSupportedTypes($refs);
if (!$refs) { if (!$refs) {
return array(); return array();
} }
@ -80,7 +79,7 @@ final class ArcanistBrowseCommitURIHardpointLoader
$uri = $commit_ref->getURI(); $uri = $commit_ref->getURI();
if ($uri !== null) { if ($uri !== null) {
$results[$key][] = id(new ArcanistBrowseURIRef()) $results[$key][] = id(new ArcanistBrowseURIRef())
->setURI() ->setURI($uri)
->setType(self::BROWSETYPE); ->setType(self::BROWSETYPE);
} }
} }

View file

@ -0,0 +1,78 @@
<?php
final class ArcanistBrowseRevisionURIHardpointLoader
extends ArcanistBrowseURIHardpointLoader {
const LOADERKEY = 'browse.uri.revision';
const BROWSETYPE = 'revision';
public function loadHardpoints(array $refs, $hardpoint) {
$query = $this->getQuery();
$working_ref = $query->getWorkingCopyRef();
if (!$working_ref) {
return array();
}
$repository_ref = $query->getRepositoryRef();
if (!$repository_ref) {
return array();
}
$refs = $this->getRefsWithSupportedTypes($refs);
if (!$refs) {
return array();
}
$this->newQuery($refs)
->needHardpoints(
array(
'commitRefs',
))
->execute();
$states = array();
$map = array();
foreach ($refs as $key => $ref) {
foreach ($ref->getCommitRefs() as $commit_ref) {
$hash = $commit_ref->getCommitHash();
$states[$hash] = id(clone $working_ref)
->setCommitRef($commit_ref);
$map[$hash][] = $key;
}
}
if (!$states) {
return array();
}
$this->newQuery($states)
->needHardpoints(
array(
'revisionRefs',
))
->execute();
$results = array();
foreach ($states as $hash => $state) {
foreach ($state->getRevisionRefs() as $revision) {
if ($revision->isClosed()) {
// Don't resolve closed revisions.
continue;
}
$uri = $revision->getURI();
foreach ($map[$hash] as $key) {
$results[$key][] = id(new ArcanistBrowseURIRef())
->setURI($uri)
->setType(self::BROWSETYPE);
}
}
}
return $results;
}
}

View file

@ -68,13 +68,6 @@ EOTEXT
$console = PhutilConsole::getConsole(); $console = PhutilConsole::getConsole();
$targets = $this->getArgument('targets'); $targets = $this->getArgument('targets');
if (!$targets) {
throw new ArcanistUsageException(
pht(
'Specify one or more paths or objects to browse. Use the '.
'command "%s" if you want to browse this directory.',
'arc browse .'));
}
$targets = array_fuse($targets); $targets = array_fuse($targets);
if (!$targets) { if (!$targets) {
@ -222,12 +215,20 @@ EOTEXT
// If anything failed to resolve, this is also an error. // If anything failed to resolve, this is also an error.
if ($zero_hits) { if ($zero_hits) {
foreach ($zero_hits as $ref) { foreach ($zero_hits as $ref) {
$token = $ref->getToken();
if ($token === null) {
echo tsprintf(
"%s\n",
pht(
'Unable to resolve default browse target.'));
} else {
echo tsprintf( echo tsprintf(
"%s\n", "%s\n",
pht( pht(
'Unable to resolve argument "%s".', 'Unable to resolve argument "%s".',
$ref->getToken())); $ref->getToken()));
} }
}
foreach ($loaders as $loader) { foreach ($loaders as $loader) {
$loader->didFailToLoadBrowseURIRefs($refs); $loader->didFailToLoadBrowseURIRefs($refs);

View file

@ -0,0 +1,41 @@
<?php
final class ArcanistGitCommitMessageHardpointLoader
extends ArcanistGitHardpointLoader {
const LOADERKEY = 'git.commit.message';
public function canLoadRef(ArcanistRef $ref) {
return ($ref instanceof ArcanistCommitRef);
}
public function canLoadHardpoint(ArcanistRef $ref, $hardpoint) {
return ($hardpoint == 'message');
}
public function loadHardpoints(array $refs, $hardpoint) {
$api = $this->getQuery()->getRepositoryAPI();
$futures = array();
foreach ($refs as $ref_key => $ref) {
$hash = $ref->getCommitHash();
$futures[$ref_key] = $api->execFutureLocal(
'log -n1 --format=%C %s --',
'%s%n%n%b',
$hash);
}
$iterator = $this->newFutureIterator($futures);
$results = array();
foreach ($iterator as $ref_key => $future) {
list($stdout) = $future->resolvex();
$results[$ref_key] = $stdout;
}
return $results;
}
}

View file

@ -33,10 +33,12 @@ final class ArcanistGitRevisionHardpointLoader
$commit->getCommitHash(), $commit->getCommitHash(),
); );
if ($commit->getTreeHash()) {
$commit_hashes[] = array( $commit_hashes[] = array(
'gttr', 'gttr',
$commit->getTreeHash(), $commit->getTreeHash(),
); );
}
foreach ($commit_hashes as $hash) { foreach ($commit_hashes as $hash) {
$hashes[] = $hash; $hashes[] = $hash;

View file

@ -28,6 +28,22 @@ final class ArcanistRevisionRef
return idx($this->parameters, 'statusName'); return idx($this->parameters, 'statusName');
} }
public function isClosed() {
// TODO: This should use sensible constants, not English language
// display text.
switch ($this->getStatusDisplayName()) {
case 'Abandoned':
case 'Closed':
return true;
}
return false;
}
public function getURI() {
return idx($this->parameters, 'uri');
}
public function getFullName() { public function getFullName() {
return pht('%s: %s', $this->getMonogram(), $this->getName()); return pht('%s: %s', $this->getMonogram(), $this->getName());
} }