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:
parent
d00de495bc
commit
84857e4890
8 changed files with 166 additions and 26 deletions
|
@ -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',
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
|
41
src/loader/ArcanistGitCommitMessageHardpointLoader.php
Normal file
41
src/loader/ArcanistGitCommitMessageHardpointLoader.php
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue