mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-25 08:12:40 +01:00
Add a "RevisionSymbolRef", revision commit messages, and make "--explore" recursive
Summary: Ref T13490. - Support resolution of revision symbols into revision objects. - Align commit inspection better against commit symbols. - Make "arc inspect --explore" recursively load all object hardpoints. - Add a "commit message" hardpoint to "RevisionRef". Test Plan: Used "arc inspect" to resolve commits and revisions. Used "--explore" to see the whole tree. Maniphest Tasks: T13490 Differential Revision: https://secure.phabricator.com/D21091
This commit is contained in:
parent
4cc05c377d
commit
1f18f25fa5
14 changed files with 286 additions and 85 deletions
|
@ -102,10 +102,9 @@ phutil_register_library_map(array(
|
|||
'ArcanistCommentSpacingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentSpacingXHPASTLinterRule.php',
|
||||
'ArcanistCommentStyleXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php',
|
||||
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCommentStyleXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistCommitRef' => 'ref/ArcanistCommitRef.php',
|
||||
'ArcanistCommitRefInspector' => 'inspector/ArcanistCommitRefInspector.php',
|
||||
'ArcanistCommitSymbolRef' => 'ref/commitsymbol/ArcanistCommitSymbolRef.php',
|
||||
'ArcanistCommitSymbolRefInspector' => 'ref/commitsymbol/ArcanistCommitSymbolRefInspector.php',
|
||||
'ArcanistCommitRef' => 'ref/commit/ArcanistCommitRef.php',
|
||||
'ArcanistCommitSymbolRef' => 'ref/commit/ArcanistCommitSymbolRef.php',
|
||||
'ArcanistCommitSymbolRefInspector' => 'ref/commit/ArcanistCommitSymbolRefInspector.php',
|
||||
'ArcanistCommitUpstreamHardpointQuery' => 'query/ArcanistCommitUpstreamHardpointQuery.php',
|
||||
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
|
||||
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
|
||||
|
@ -208,7 +207,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php',
|
||||
'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php',
|
||||
'ArcanistGitCommitMessageHardpointQuery' => 'query/ArcanistGitCommitMessageHardpointQuery.php',
|
||||
'ArcanistGitCommitSymbolCommitHardpointQuery' => 'ref/commitsymbol/ArcanistGitCommitSymbolCommitHardpointQuery.php',
|
||||
'ArcanistGitCommitSymbolCommitHardpointQuery' => 'ref/commit/ArcanistGitCommitSymbolCommitHardpointQuery.php',
|
||||
'ArcanistGitLandEngine' => 'land/ArcanistGitLandEngine.php',
|
||||
'ArcanistGitUpstreamPath' => 'repository/api/ArcanistGitUpstreamPath.php',
|
||||
'ArcanistGitWorkingCopy' => 'workingcopy/ArcanistGitWorkingCopy.php',
|
||||
|
@ -398,8 +397,12 @@ phutil_register_library_map(array(
|
|||
'ArcanistReusedIteratorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistReusedIteratorXHPASTLinterRule.php',
|
||||
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistReusedIteratorXHPASTLinterRuleTestCase.php',
|
||||
'ArcanistRevertWorkflow' => 'workflow/ArcanistRevertWorkflow.php',
|
||||
'ArcanistRevisionRef' => 'ref/ArcanistRevisionRef.php',
|
||||
'ArcanistRevisionCommitMessageHardpointQuery' => 'ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php',
|
||||
'ArcanistRevisionRef' => 'ref/revision/ArcanistRevisionRef.php',
|
||||
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
|
||||
'ArcanistRevisionSymbolHardpointQuery' => 'ref/revision/ArcanistRevisionSymbolHardpointQuery.php',
|
||||
'ArcanistRevisionSymbolRef' => 'ref/revision/ArcanistRevisionSymbolRef.php',
|
||||
'ArcanistRevisionSymbolRefInspector' => 'ref/revision/ArcanistRevisionSymbolRefInspector.php',
|
||||
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
|
||||
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
|
||||
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
|
||||
|
@ -432,6 +435,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistSubversionAPI' => 'repository/api/ArcanistSubversionAPI.php',
|
||||
'ArcanistSubversionWorkingCopy' => 'workingcopy/ArcanistSubversionWorkingCopy.php',
|
||||
'ArcanistSummaryLintRenderer' => 'lint/renderer/ArcanistSummaryLintRenderer.php',
|
||||
'ArcanistSymbolRef' => 'ref/symbol/ArcanistSymbolRef.php',
|
||||
'ArcanistSyntaxErrorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSyntaxErrorXHPASTLinterRule.php',
|
||||
'ArcanistSystemConfigurationSource' => 'config/source/ArcanistSystemConfigurationSource.php',
|
||||
'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php',
|
||||
|
@ -1068,8 +1072,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistCommitRef' => 'ArcanistRef',
|
||||
'ArcanistCommitRefInspector' => 'ArcanistRefInspector',
|
||||
'ArcanistCommitSymbolRef' => 'ArcanistRef',
|
||||
'ArcanistCommitSymbolRef' => 'ArcanistSymbolRef',
|
||||
'ArcanistCommitSymbolRefInspector' => 'ArcanistRefInspector',
|
||||
'ArcanistCommitUpstreamHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
|
||||
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
|
||||
|
@ -1363,8 +1366,12 @@ phutil_register_library_map(array(
|
|||
'ArcanistReusedIteratorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistReusedIteratorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
|
||||
'ArcanistRevertWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistRevisionCommitMessageHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
|
||||
'ArcanistRevisionRef' => 'ArcanistRef',
|
||||
'ArcanistRevisionRefSource' => 'Phobject',
|
||||
'ArcanistRevisionSymbolHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
|
||||
'ArcanistRevisionSymbolRef' => 'ArcanistSymbolRef',
|
||||
'ArcanistRevisionSymbolRefInspector' => 'ArcanistRefInspector',
|
||||
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
|
||||
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
|
||||
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
|
||||
|
@ -1396,6 +1403,7 @@ phutil_register_library_map(array(
|
|||
'ArcanistSubversionAPI' => 'ArcanistRepositoryAPI',
|
||||
'ArcanistSubversionWorkingCopy' => 'ArcanistWorkingCopy',
|
||||
'ArcanistSummaryLintRenderer' => 'ArcanistLintRenderer',
|
||||
'ArcanistSymbolRef' => 'ArcanistRef',
|
||||
'ArcanistSyntaxErrorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
|
||||
'ArcanistSystemConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
|
||||
'ArcanistTasksWorkflow' => 'ArcanistWorkflow',
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistCommitRefInspector
|
||||
extends ArcanistRefInspector {
|
||||
|
||||
public function getInspectFunctionName() {
|
||||
return 'commit';
|
||||
}
|
||||
|
||||
public function newInspectRef(array $argv) {
|
||||
if (count($argv) !== 1) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Expected exactly one argument to "commit(...)" with a '.
|
||||
'commit hash.'));
|
||||
}
|
||||
|
||||
return id(new ArcanistCommitRef())
|
||||
->setCommitHash($argv[0]);
|
||||
}
|
||||
|
||||
}
|
10
src/ref/commit/ArcanistCommitSymbolRef.php
Normal file
10
src/ref/commit/ArcanistCommitSymbolRef.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistCommitSymbolRef
|
||||
extends ArcanistSymbolRef {
|
||||
|
||||
public function getRefDisplayName() {
|
||||
return pht('Commit Symbol "%s"', $this->getSymbol());
|
||||
}
|
||||
|
||||
}
|
|
@ -4,14 +4,14 @@ final class ArcanistCommitSymbolRefInspector
|
|||
extends ArcanistRefInspector {
|
||||
|
||||
public function getInspectFunctionName() {
|
||||
return 'symbol';
|
||||
return 'commit';
|
||||
}
|
||||
|
||||
public function newInspectRef(array $argv) {
|
||||
if (count($argv) !== 1) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Expected exactly one argument to "symbol(...)" with a '.
|
||||
'Expected exactly one argument to "commit(...)" with a '.
|
||||
'commit symbol.'));
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ final class ArcanistGitCommitSymbolCommitHardpointQuery
|
|||
|
||||
public function getHardpoints() {
|
||||
return array(
|
||||
ArcanistCommitSymbolRef::HARDPOINT_COMMIT,
|
||||
ArcanistCommitSymbolRef::HARDPOINT_OBJECT,
|
||||
);
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistCommitSymbolRef
|
||||
extends ArcanistRef {
|
||||
|
||||
private $symbol;
|
||||
|
||||
const HARDPOINT_COMMIT = 'ref.commit-symbol';
|
||||
|
||||
public function getRefDisplayName() {
|
||||
return pht('Commit Symbol "%s"', $this->getSymbol());
|
||||
}
|
||||
|
||||
protected function newHardpoints() {
|
||||
return array(
|
||||
$this->newHardpoint(self::HARDPOINT_COMMIT),
|
||||
);
|
||||
}
|
||||
|
||||
public function setSymbol($symbol) {
|
||||
$this->symbol = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSymbol() {
|
||||
return $this->symbol;
|
||||
}
|
||||
|
||||
public function attachCommit(ArcanistCommitRef $commit) {
|
||||
return $this->attachHardpoint(self::HARDPOINT_COMMIT, $commit);
|
||||
}
|
||||
|
||||
public function getCommit() {
|
||||
return $this->getHardpoint(self::HARDPOINT_COMMIT);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistRevisionCommitMessageHardpointQuery
|
||||
extends ArcanistWorkflowHardpointQuery {
|
||||
|
||||
public function getHardpoints() {
|
||||
return array(
|
||||
ArcanistRevisionRef::HARDPOINT_COMMITMESSAGE,
|
||||
);
|
||||
}
|
||||
|
||||
protected function canLoadRef(ArcanistRef $ref) {
|
||||
return ($ref instanceof ArcanistRevisionRef);
|
||||
}
|
||||
|
||||
public function loadHardpoint(array $refs, $hardpoint) {
|
||||
$api = $this->getRepositoryAPI();
|
||||
|
||||
// NOTE: This is not efficient, but no bulk API exists at time of
|
||||
// writing and no callers bulk-load this data.
|
||||
|
||||
$results = array();
|
||||
foreach ($refs as $key => $ref) {
|
||||
$message = (yield $this->yieldConduit(
|
||||
'differential.getcommitmessage',
|
||||
array(
|
||||
'revision_id' => $ref->getID(),
|
||||
'edit' => false,
|
||||
)));
|
||||
|
||||
$results[$key] = $message;
|
||||
}
|
||||
|
||||
yield $this->yieldMap($results);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,6 +3,8 @@
|
|||
final class ArcanistRevisionRef
|
||||
extends ArcanistRef {
|
||||
|
||||
const HARDPOINT_COMMITMESSAGE = 'ref.revision.commitmessage';
|
||||
|
||||
private $parameters;
|
||||
private $sources = array();
|
||||
|
||||
|
@ -10,6 +12,12 @@ final class ArcanistRevisionRef
|
|||
return pht('Revision %s', $this->getMonogram());
|
||||
}
|
||||
|
||||
protected function newHardpoints() {
|
||||
return array(
|
||||
$this->newHardpoint(self::HARDPOINT_COMMITMESSAGE),
|
||||
);
|
||||
}
|
||||
|
||||
public static function newFromConduit(array $dict) {
|
||||
$ref = new self();
|
||||
$ref->parameters = $dict;
|
||||
|
@ -45,7 +53,7 @@ final class ArcanistRevisionRef
|
|||
}
|
||||
|
||||
public function getID() {
|
||||
return idx($this->parameters, 'id');
|
||||
return (int)idx($this->parameters, 'id');
|
||||
}
|
||||
|
||||
public function getPHID() {
|
40
src/ref/revision/ArcanistRevisionSymbolHardpointQuery.php
Normal file
40
src/ref/revision/ArcanistRevisionSymbolHardpointQuery.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistRevisionSymbolHardpointQuery
|
||||
extends ArcanistWorkflowHardpointQuery {
|
||||
|
||||
public function getHardpoints() {
|
||||
return array(
|
||||
ArcanistRevisionSymbolRef::HARDPOINT_OBJECT,
|
||||
);
|
||||
}
|
||||
|
||||
protected function canLoadRef(ArcanistRef $ref) {
|
||||
return ($ref instanceof ArcanistRevisionSymbolRef);
|
||||
}
|
||||
|
||||
public function loadHardpoint(array $refs, $hardpoint) {
|
||||
$id_map = mpull($refs, 'getSymbol');
|
||||
$id_set = array_fuse($id_map);
|
||||
|
||||
$revisions = (yield $this->yieldConduit(
|
||||
'differential.query',
|
||||
array(
|
||||
'ids' => $id_set,
|
||||
)));
|
||||
|
||||
$refs = array();
|
||||
foreach ($revisions as $revision) {
|
||||
$ref = ArcanistRevisionRef::newFromConduit($revision);
|
||||
$refs[$ref->getID()] = $ref;
|
||||
}
|
||||
|
||||
$results = array();
|
||||
foreach ($id_map as $key => $id) {
|
||||
$results[$key] = idx($refs, $id);
|
||||
}
|
||||
|
||||
yield $this->yieldMap($results);
|
||||
}
|
||||
|
||||
}
|
25
src/ref/revision/ArcanistRevisionSymbolRef.php
Normal file
25
src/ref/revision/ArcanistRevisionSymbolRef.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistRevisionSymbolRef
|
||||
extends ArcanistSymbolRef {
|
||||
|
||||
public function getRefDisplayName() {
|
||||
return pht('Revision Symbol "%s"', $this->getSymbol());
|
||||
}
|
||||
|
||||
protected function resolveSymbol($symbol) {
|
||||
$matches = null;
|
||||
|
||||
if (!preg_match('/^[Dd]?([1-9]\d*)\z/', $symbol, $matches)) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'The format of revision symbol "%s" is unrecognized. '.
|
||||
'Expected a revision monogram like "D123", or a '.
|
||||
'revision ID like "123".',
|
||||
$symbol));
|
||||
}
|
||||
|
||||
return (int)$matches[1];
|
||||
}
|
||||
|
||||
}
|
22
src/ref/revision/ArcanistRevisionSymbolRefInspector.php
Normal file
22
src/ref/revision/ArcanistRevisionSymbolRefInspector.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistRevisionSymbolRefInspector
|
||||
extends ArcanistRefInspector {
|
||||
|
||||
public function getInspectFunctionName() {
|
||||
return 'revision';
|
||||
}
|
||||
|
||||
public function newInspectRef(array $argv) {
|
||||
if (count($argv) !== 1) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Expected exactly one argument to "revision(...)" with a '.
|
||||
'revision symbol.'));
|
||||
}
|
||||
|
||||
return id(new ArcanistRevisionSymbolRef())
|
||||
->setSymbol($argv[0]);
|
||||
}
|
||||
|
||||
}
|
39
src/ref/symbol/ArcanistSymbolRef.php
Normal file
39
src/ref/symbol/ArcanistSymbolRef.php
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
abstract class ArcanistSymbolRef
|
||||
extends ArcanistRef {
|
||||
|
||||
private $symbol;
|
||||
|
||||
const HARDPOINT_OBJECT = 'ref.symbol.object';
|
||||
|
||||
protected function newHardpoints() {
|
||||
return array(
|
||||
$this->newHardpoint(self::HARDPOINT_OBJECT),
|
||||
);
|
||||
}
|
||||
|
||||
final public function setSymbol($symbol) {
|
||||
$symbol = $this->resolveSymbol($symbol);
|
||||
|
||||
$this->symbol = $symbol;
|
||||
return $this;
|
||||
}
|
||||
|
||||
final public function getSymbol() {
|
||||
return $this->symbol;
|
||||
}
|
||||
|
||||
final public function attachObject(ArcanistRef $object) {
|
||||
return $this->attachHardpoint(self::HARDPOINT_OBJECT, $object);
|
||||
}
|
||||
|
||||
final public function getObject() {
|
||||
return $this->getHardpoint(self::HARDPOINT_OBJECT);
|
||||
}
|
||||
|
||||
protected function resolveSymbol($symbol) {
|
||||
return $symbol;
|
||||
}
|
||||
|
||||
}
|
|
@ -51,7 +51,6 @@ EOTEXT
|
|||
}
|
||||
|
||||
$all_refs = array();
|
||||
$ref_lists = array();
|
||||
foreach ($objects as $description) {
|
||||
$matches = null;
|
||||
$pattern = '/^([\w-]+)(?:\(([^)]+)\))?\z/';
|
||||
|
@ -84,23 +83,11 @@ EOTEXT
|
|||
|
||||
$ref = $inspector->newInspectRef($arguments);
|
||||
|
||||
$ref_lists[get_class($ref)][] = $ref;
|
||||
$all_refs[] = $ref;
|
||||
}
|
||||
|
||||
if ($is_explore) {
|
||||
foreach ($ref_lists as $ref_class => $refs) {
|
||||
$ref = head($refs);
|
||||
|
||||
$hardpoint_list = $ref->getHardpointList();
|
||||
$hardpoints = $hardpoint_list->getHardpoints();
|
||||
|
||||
if ($hardpoints) {
|
||||
$hardpoint_keys = mpull($hardpoints, 'getHardpointKey');
|
||||
|
||||
$this->loadHardpoints($refs, $hardpoint_keys);
|
||||
}
|
||||
}
|
||||
$this->exploreRefs($all_refs);
|
||||
}
|
||||
|
||||
$list = array();
|
||||
|
@ -214,4 +201,88 @@ EOTEXT
|
|||
return $out;
|
||||
}
|
||||
|
||||
private function exploreRefs(array $refs) {
|
||||
$seen = array();
|
||||
$look = $refs;
|
||||
|
||||
while ($look) {
|
||||
$ref_map = $this->getRefsByClass($look);
|
||||
$look = array();
|
||||
|
||||
$children = $this->inspectHardpoints($ref_map);
|
||||
|
||||
foreach ($children as $child) {
|
||||
$hash = spl_object_hash($child);
|
||||
|
||||
if (isset($seen[$hash])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$seen[$hash] = true;
|
||||
$look[] = $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getRefsByClass(array $refs) {
|
||||
$ref_lists = array();
|
||||
foreach ($refs as $ref) {
|
||||
$ref_lists[get_class($ref)][] = $ref;
|
||||
}
|
||||
|
||||
foreach ($ref_lists as $ref_class => $refs) {
|
||||
$typical_ref = head($refs);
|
||||
|
||||
$hardpoint_list = $typical_ref->getHardpointList();
|
||||
$hardpoints = $hardpoint_list->getHardpoints();
|
||||
|
||||
if (!$hardpoints) {
|
||||
unset($ref_lists[$ref_class]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$hardpoint_keys = mpull($hardpoints, 'getHardpointKey');
|
||||
|
||||
$ref_lists[$ref_class] = array(
|
||||
'keys' => $hardpoint_keys,
|
||||
'refs' => $refs,
|
||||
);
|
||||
}
|
||||
|
||||
return $ref_lists;
|
||||
}
|
||||
|
||||
private function inspectHardpoints(array $ref_lists) {
|
||||
foreach ($ref_lists as $ref_class => $spec) {
|
||||
$refs = $spec['refs'];
|
||||
$keys = $spec['keys'];
|
||||
|
||||
$this->loadHardpoints($refs, $keys);
|
||||
}
|
||||
|
||||
$child_refs = array();
|
||||
|
||||
foreach ($ref_lists as $ref_class => $spec) {
|
||||
$refs = $spec['refs'];
|
||||
$keys = $spec['keys'];
|
||||
foreach ($refs as $ref) {
|
||||
foreach ($keys as $key) {
|
||||
$value = $ref->getHardpoint($key);
|
||||
|
||||
if (!is_array($value)) {
|
||||
$value = array($value);
|
||||
}
|
||||
|
||||
foreach ($value as $child) {
|
||||
if ($child instanceof ArcanistRef) {
|
||||
$child_refs[] = $child;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $child_refs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue