diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -102,10 +102,9 @@ '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 @@ '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 @@ '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 @@ '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 @@ 'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistCommitRef' => 'ArcanistRef', - 'ArcanistCommitRefInspector' => 'ArcanistRefInspector', - 'ArcanistCommitSymbolRef' => 'ArcanistRef', + 'ArcanistCommitSymbolRef' => 'ArcanistSymbolRef', 'ArcanistCommitSymbolRefInspector' => 'ArcanistRefInspector', 'ArcanistCommitUpstreamHardpointQuery' => 'ArcanistWorkflowHardpointQuery', 'ArcanistCommitWorkflow' => 'ArcanistWorkflow', @@ -1363,8 +1366,12 @@ '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 @@ 'ArcanistSubversionAPI' => 'ArcanistRepositoryAPI', 'ArcanistSubversionWorkingCopy' => 'ArcanistWorkingCopy', 'ArcanistSummaryLintRenderer' => 'ArcanistLintRenderer', + 'ArcanistSymbolRef' => 'ArcanistRef', 'ArcanistSyntaxErrorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistSystemConfigurationSource' => 'ArcanistFilesystemConfigurationSource', 'ArcanistTasksWorkflow' => 'ArcanistWorkflow', diff --git a/src/inspector/ArcanistCommitRefInspector.php b/src/inspector/ArcanistCommitRefInspector.php deleted file mode 100644 --- a/src/inspector/ArcanistCommitRefInspector.php +++ /dev/null @@ -1,22 +0,0 @@ -setCommitHash($argv[0]); - } - -} diff --git a/src/ref/ArcanistCommitRef.php b/src/ref/commit/ArcanistCommitRef.php rename from src/ref/ArcanistCommitRef.php rename to src/ref/commit/ArcanistCommitRef.php diff --git a/src/ref/commit/ArcanistCommitSymbolRef.php b/src/ref/commit/ArcanistCommitSymbolRef.php new file mode 100644 --- /dev/null +++ b/src/ref/commit/ArcanistCommitSymbolRef.php @@ -0,0 +1,10 @@ +getSymbol()); + } + +} diff --git a/src/ref/commitsymbol/ArcanistCommitSymbolRefInspector.php b/src/ref/commit/ArcanistCommitSymbolRefInspector.php rename from src/ref/commitsymbol/ArcanistCommitSymbolRefInspector.php rename to src/ref/commit/ArcanistCommitSymbolRefInspector.php --- a/src/ref/commitsymbol/ArcanistCommitSymbolRefInspector.php +++ b/src/ref/commit/ArcanistCommitSymbolRefInspector.php @@ -4,14 +4,14 @@ 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.')); } diff --git a/src/ref/commitsymbol/ArcanistGitCommitSymbolCommitHardpointQuery.php b/src/ref/commit/ArcanistGitCommitSymbolCommitHardpointQuery.php rename from src/ref/commitsymbol/ArcanistGitCommitSymbolCommitHardpointQuery.php rename to src/ref/commit/ArcanistGitCommitSymbolCommitHardpointQuery.php --- a/src/ref/commitsymbol/ArcanistGitCommitSymbolCommitHardpointQuery.php +++ b/src/ref/commit/ArcanistGitCommitSymbolCommitHardpointQuery.php @@ -5,7 +5,7 @@ public function getHardpoints() { return array( - ArcanistCommitSymbolRef::HARDPOINT_COMMIT, + ArcanistCommitSymbolRef::HARDPOINT_OBJECT, ); } diff --git a/src/ref/commitsymbol/ArcanistCommitSymbolRef.php b/src/ref/commitsymbol/ArcanistCommitSymbolRef.php deleted file mode 100644 --- a/src/ref/commitsymbol/ArcanistCommitSymbolRef.php +++ /dev/null @@ -1,37 +0,0 @@ -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); - } - -} diff --git a/src/ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php b/src/ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php new file mode 100644 --- /dev/null +++ b/src/ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php @@ -0,0 +1,37 @@ +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); + } + +} diff --git a/src/ref/ArcanistRevisionRef.php b/src/ref/revision/ArcanistRevisionRef.php rename from src/ref/ArcanistRevisionRef.php rename to src/ref/revision/ArcanistRevisionRef.php --- a/src/ref/ArcanistRevisionRef.php +++ b/src/ref/revision/ArcanistRevisionRef.php @@ -3,6 +3,8 @@ final class ArcanistRevisionRef extends ArcanistRef { + const HARDPOINT_COMMITMESSAGE = 'ref.revision.commitmessage'; + private $parameters; private $sources = array(); @@ -10,6 +12,12 @@ 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 @@ } public function getID() { - return idx($this->parameters, 'id'); + return (int)idx($this->parameters, 'id'); } public function getPHID() { diff --git a/src/ref/revision/ArcanistRevisionSymbolHardpointQuery.php b/src/ref/revision/ArcanistRevisionSymbolHardpointQuery.php new file mode 100644 --- /dev/null +++ b/src/ref/revision/ArcanistRevisionSymbolHardpointQuery.php @@ -0,0 +1,40 @@ +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); + } + +} diff --git a/src/ref/revision/ArcanistRevisionSymbolRef.php b/src/ref/revision/ArcanistRevisionSymbolRef.php new file mode 100644 --- /dev/null +++ b/src/ref/revision/ArcanistRevisionSymbolRef.php @@ -0,0 +1,25 @@ +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]; + } + +} diff --git a/src/ref/commitsymbol/ArcanistCommitSymbolRefInspector.php b/src/ref/revision/ArcanistRevisionSymbolRefInspector.php rename from src/ref/commitsymbol/ArcanistCommitSymbolRefInspector.php rename to src/ref/revision/ArcanistRevisionSymbolRefInspector.php --- a/src/ref/commitsymbol/ArcanistCommitSymbolRefInspector.php +++ b/src/ref/revision/ArcanistRevisionSymbolRefInspector.php @@ -1,21 +1,21 @@ setSymbol($argv[0]); } diff --git a/src/ref/symbol/ArcanistSymbolRef.php b/src/ref/symbol/ArcanistSymbolRef.php new file mode 100644 --- /dev/null +++ b/src/ref/symbol/ArcanistSymbolRef.php @@ -0,0 +1,39 @@ +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; + } + +} diff --git a/src/workflow/ArcanistInspectWorkflow.php b/src/workflow/ArcanistInspectWorkflow.php --- a/src/workflow/ArcanistInspectWorkflow.php +++ b/src/workflow/ArcanistInspectWorkflow.php @@ -51,7 +51,6 @@ } $all_refs = array(); - $ref_lists = array(); foreach ($objects as $description) { $matches = null; $pattern = '/^([\w-]+)(?:\(([^)]+)\))?\z/'; @@ -84,23 +83,11 @@ $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 @@ 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; + } + }