Page MenuHomePhabricator

D21078.diff
No OneTemporary

D21078.diff

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
@@ -54,6 +54,7 @@
'ArcanistBraceFormattingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistBraceFormattingXHPASTLinterRule.php',
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistBraceFormattingXHPASTLinterRuleTestCase.php',
'ArcanistBranchRef' => 'ref/ArcanistBranchRef.php',
+ 'ArcanistBranchRefPro' => 'ref/ArcanistBranchRefPro.php',
'ArcanistBranchWorkflow' => 'workflow/ArcanistBranchWorkflow.php',
'ArcanistBrowseCommitHardpointLoader' => 'browse/loader/ArcanistBrowseCommitHardpointLoader.php',
'ArcanistBrowseCommitURIHardpointLoader' => 'browse/loader/ArcanistBrowseCommitURIHardpointLoader.php',
@@ -102,7 +103,10 @@
'ArcanistCommentStyleXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistCommentStyleXHPASTLinterRule.php',
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistCommentStyleXHPASTLinterRuleTestCase.php',
'ArcanistCommitRef' => 'ref/ArcanistCommitRef.php',
+ 'ArcanistCommitRefInspector' => 'inspector/ArcanistCommitRefInspector.php',
+ 'ArcanistCommitRefPro' => 'ref/ArcanistCommitRefPro.php',
'ArcanistCommitUpstreamHardpointLoader' => 'loader/ArcanistCommitUpstreamHardpointLoader.php',
+ 'ArcanistCommitUpstreamHardpointQuery' => 'query/ArcanistCommitUpstreamHardpointQuery.php',
'ArcanistCommitWorkflow' => 'workflow/ArcanistCommitWorkflow.php',
'ArcanistCompilerLintRenderer' => 'lint/renderer/ArcanistCompilerLintRenderer.php',
'ArcanistComposerLinter' => 'lint/linter/ArcanistComposerLinter.php',
@@ -203,6 +207,7 @@
'ArcanistGetConfigWorkflow' => 'workflow/ArcanistGetConfigWorkflow.php',
'ArcanistGitAPI' => 'repository/api/ArcanistGitAPI.php',
'ArcanistGitCommitMessageHardpointLoader' => 'loader/ArcanistGitCommitMessageHardpointLoader.php',
+ 'ArcanistGitCommitMessageHardpointQuery' => 'query/ArcanistGitCommitMessageHardpointQuery.php',
'ArcanistGitHardpointLoader' => 'loader/ArcanistGitHardpointLoader.php',
'ArcanistGitLandEngine' => 'land/ArcanistGitLandEngine.php',
'ArcanistGitRevisionHardpointLoader' => 'loader/ArcanistGitRevisionHardpointLoader.php',
@@ -226,6 +231,7 @@
'ArcanistHardpointRequest' => 'hardpoint/ArcanistHardpointRequest.php',
'ArcanistHardpointRequestList' => 'hardpoint/ArcanistHardpointRequestList.php',
'ArcanistHardpointTask' => 'hardpoint/ArcanistHardpointTask.php',
+ 'ArcanistHardpointTaskResult' => 'hardpoint/ArcanistHardpointTaskResult.php',
'ArcanistHelpWorkflow' => 'toolset/workflow/ArcanistHelpWorkflow.php',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule.php',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase.php',
@@ -245,6 +251,7 @@
'ArcanistInlineHTMLXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInlineHTMLXHPASTLinterRuleTestCase.php',
'ArcanistInnerFunctionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInnerFunctionXHPASTLinterRule.php',
'ArcanistInnerFunctionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInnerFunctionXHPASTLinterRuleTestCase.php',
+ 'ArcanistInspectWorkflow' => 'workflow/ArcanistInspectWorkflow.php',
'ArcanistInstallCertificateWorkflow' => 'workflow/ArcanistInstallCertificateWorkflow.php',
'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistInstanceOfOperatorXHPASTLinterRule.php',
'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistInstanceofOperatorXHPASTLinterRuleTestCase.php',
@@ -381,6 +388,8 @@
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistRaggedClassTreeEdgeXHPASTLinterRule.php',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase.php',
'ArcanistRef' => 'ref/ArcanistRef.php',
+ 'ArcanistRefInspector' => 'inspector/ArcanistRefInspector.php',
+ 'ArcanistRefPro' => 'ref/ArcanistRefPro.php',
'ArcanistRefQuery' => 'ref/ArcanistRefQuery.php',
'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php',
'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php',
@@ -489,12 +498,15 @@
'ArcanistWildConfigOption' => 'config/option/ArcanistWildConfigOption.php',
'ArcanistWorkflow' => 'workflow/ArcanistWorkflow.php',
'ArcanistWorkflowArgument' => 'toolset/ArcanistWorkflowArgument.php',
+ 'ArcanistWorkflowHardpointQuery' => 'toolset/query/ArcanistWorkflowHardpointQuery.php',
'ArcanistWorkflowInformation' => 'toolset/ArcanistWorkflowInformation.php',
'ArcanistWorkingCopy' => 'workingcopy/ArcanistWorkingCopy.php',
+ 'ArcanistWorkingCopyCommitHardpointQuery' => 'query/ArcanistWorkingCopyCommitHardpointQuery.php',
'ArcanistWorkingCopyConfigurationSource' => 'config/source/ArcanistWorkingCopyConfigurationSource.php',
'ArcanistWorkingCopyIdentity' => 'workingcopyidentity/ArcanistWorkingCopyIdentity.php',
'ArcanistWorkingCopyPath' => 'workingcopy/ArcanistWorkingCopyPath.php',
'ArcanistWorkingCopyStateRef' => 'ref/ArcanistWorkingCopyStateRef.php',
+ 'ArcanistWorkingCopyStateRefPro' => 'ref/ArcanistWorkingCopyStateRefPro.php',
'ArcanistXHPASTLintNamingHook' => 'lint/linter/xhpast/ArcanistXHPASTLintNamingHook.php',
'ArcanistXHPASTLintNamingHookTestCase' => 'lint/linter/xhpast/__tests__/ArcanistXHPASTLintNamingHookTestCase.php',
'ArcanistXHPASTLintSwitchHook' => 'lint/linter/xhpast/ArcanistXHPASTLintSwitchHook.php',
@@ -1010,6 +1022,7 @@
'ArcanistBraceFormattingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBranchRef' => 'ArcanistRef',
+ 'ArcanistBranchRefPro' => 'ArcanistRefPro',
'ArcanistBranchWorkflow' => 'ArcanistFeatureWorkflow',
'ArcanistBrowseCommitHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistBrowseCommitURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
@@ -1058,7 +1071,10 @@
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCommitRef' => 'ArcanistRef',
+ 'ArcanistCommitRefInspector' => 'ArcanistRefInspector',
+ 'ArcanistCommitRefPro' => 'ArcanistRefPro',
'ArcanistCommitUpstreamHardpointLoader' => 'ArcanistHardpointLoader',
+ 'ArcanistCommitUpstreamHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
'ArcanistComposerLinter' => 'ArcanistLinter',
@@ -1159,6 +1175,7 @@
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
'ArcanistGitCommitMessageHardpointLoader' => 'ArcanistGitHardpointLoader',
+ 'ArcanistGitCommitMessageHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
'ArcanistGitHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistGitLandEngine' => 'ArcanistLandEngine',
'ArcanistGitRevisionHardpointLoader' => 'ArcanistGitHardpointLoader',
@@ -1182,6 +1199,7 @@
'ArcanistHardpointRequest' => 'Phobject',
'ArcanistHardpointRequestList' => 'Phobject',
'ArcanistHardpointTask' => 'Phobject',
+ 'ArcanistHardpointTaskResult' => 'Phobject',
'ArcanistHelpWorkflow' => 'ArcanistWorkflow',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@@ -1201,6 +1219,7 @@
'ArcanistInlineHTMLXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInnerFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInnerFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
+ 'ArcanistInspectWorkflow' => 'ArcanistArcWorkflow',
'ArcanistInstallCertificateWorkflow' => 'ArcanistWorkflow',
'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@@ -1337,6 +1356,8 @@
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistRef' => 'Phobject',
+ 'ArcanistRefInspector' => 'Phobject',
+ 'ArcanistRefPro' => 'ArcanistHardpointObject',
'ArcanistRefQuery' => 'Phobject',
'ArcanistRepositoryAPI' => 'Phobject',
'ArcanistRepositoryAPIMiscTestCase' => 'PhutilTestCase',
@@ -1444,12 +1465,15 @@
'ArcanistWildConfigOption' => 'ArcanistConfigOption',
'ArcanistWorkflow' => 'Phobject',
'ArcanistWorkflowArgument' => 'Phobject',
+ 'ArcanistWorkflowHardpointQuery' => 'ArcanistHardpointQuery',
'ArcanistWorkflowInformation' => 'Phobject',
'ArcanistWorkingCopy' => 'Phobject',
+ 'ArcanistWorkingCopyCommitHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
'ArcanistWorkingCopyConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistWorkingCopyIdentity' => 'Phobject',
'ArcanistWorkingCopyPath' => 'Phobject',
'ArcanistWorkingCopyStateRef' => 'ArcanistRef',
+ 'ArcanistWorkingCopyStateRefPro' => 'ArcanistRefPro',
'ArcanistXHPASTLintNamingHook' => 'Phobject',
'ArcanistXHPASTLintNamingHookTestCase' => 'PhutilTestCase',
'ArcanistXHPASTLintSwitchHook' => 'Phobject',
diff --git a/src/hardpoint/ArcanistHardpointList.php b/src/hardpoint/ArcanistHardpointList.php
--- a/src/hardpoint/ArcanistHardpointList.php
+++ b/src/hardpoint/ArcanistHardpointList.php
@@ -46,6 +46,10 @@
return isset($this->attached[$hardpoint]);
}
+ public function getHardpoints() {
+ return $this->hardpoints;
+ }
+
public function getHardpointDefinition($object, $hardpoint) {
if (!$this->hasHardpoint($object, $hardpoint)) {
throw new Exception(
diff --git a/src/hardpoint/ArcanistHardpointTask.php b/src/hardpoint/ArcanistHardpointTask.php
--- a/src/hardpoint/ArcanistHardpointTask.php
+++ b/src/hardpoint/ArcanistHardpointTask.php
@@ -100,6 +100,7 @@
$generator->next();
}
+ $generator_result = null;
if ($generator->valid()) {
$result = $generator->current();
@@ -152,17 +153,25 @@
return true;
}
- throw new Exception(
- pht(
- 'Hardpoint generator (for query "%s") yielded an unexpected '.
- 'value. Generators may only yield "Future" or '.
- '"ArcanistHardpointRequest" objects, got "%s".',
- get_class($query),
- phutil_describe_type($result)));
+ if ($result instanceof ArcanistHardpointTaskResult) {
+ $generator_result = $result;
+ } else {
+ throw new Exception(
+ pht(
+ 'Hardpoint generator (for query "%s") yielded an unexpected '.
+ 'value (of type "%s").',
+ get_class($query),
+ phutil_describe_type($result)));
+ }
}
$this->generator = null;
- $result = $generator->getReturn();
+
+ if ($generator_result !== null) {
+ $result = $generator_result->getValue();
+ } else {
+ $result = $generator->getReturn();
+ }
$this->attachResult($result);
diff --git a/src/hardpoint/ArcanistHardpointTaskResult.php b/src/hardpoint/ArcanistHardpointTaskResult.php
new file mode 100644
--- /dev/null
+++ b/src/hardpoint/ArcanistHardpointTaskResult.php
@@ -0,0 +1,16 @@
+<?php
+
+final class ArcanistHardpointTaskResult
+ extends Phobject {
+
+ private $value;
+
+ public function __construct($value) {
+ $this->value = $value;
+ }
+
+ public function getValue() {
+ return $this->value;
+ }
+
+}
diff --git a/src/inspector/ArcanistCommitRefInspector.php b/src/inspector/ArcanistCommitRefInspector.php
new file mode 100644
--- /dev/null
+++ b/src/inspector/ArcanistCommitRefInspector.php
@@ -0,0 +1,22 @@
+<?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 ArcanistCommitRefPro())
+ ->setCommitHash($argv[0]);
+ }
+
+}
diff --git a/src/inspector/ArcanistRefInspector.php b/src/inspector/ArcanistRefInspector.php
new file mode 100644
--- /dev/null
+++ b/src/inspector/ArcanistRefInspector.php
@@ -0,0 +1,16 @@
+<?php
+
+abstract class ArcanistRefInspector
+ extends Phobject {
+
+ abstract public function getInspectFunctionName();
+ abstract public function newInspectRef(array $argv);
+
+ final public static function getAllInspectors() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getInspectFunctionName')
+ ->execute();
+ }
+
+}
diff --git a/src/query/ArcanistCommitUpstreamHardpointQuery.php b/src/query/ArcanistCommitUpstreamHardpointQuery.php
new file mode 100644
--- /dev/null
+++ b/src/query/ArcanistCommitUpstreamHardpointQuery.php
@@ -0,0 +1,53 @@
+<?php
+
+final class ArcanistCommitUpstreamHardpointQuery
+ extends ArcanistWorkflowHardpointQuery {
+
+ public function getHardpoints() {
+ return array(
+ ArcanistCommitRefPro::HARDPOINT_UPSTREAM,
+ );
+ }
+
+ protected function canLoadRef(ArcanistRefPro $ref) {
+ return ($ref instanceof ArcanistCommitRefPro);
+ }
+
+ public function loadHardpoint(array $refs, $hardpoint) {
+ $repository_ref = (yield $this->yieldRepositoryRef());
+ if (!$repository_ref) {
+ yield $this->yieldValue($refs, null);
+ }
+ $repository_phid = $repository_ref->getPHID();
+
+ $commit_map = array();
+ foreach ($refs as $key => $ref) {
+ $hash = $ref->getCommitHash();
+ $commit_map[$hash][] = $key;
+ }
+
+ $commit_info = (yield $this->yieldConduit(
+ 'diffusion.querycommits',
+ array(
+ 'repositoryPHID' => $repository_phid,
+ 'names' => array_keys($commit_map),
+ )));
+
+ $results = array();
+ foreach ($commit_map as $hash => $keys) {
+ $commit_phid = idx($commit_info['identifierMap'], $hash);
+ if ($commit_phid) {
+ $commit_data = idx($commit_info['data'], $commit_phid);
+ } else {
+ $commit_data = null;
+ }
+
+ foreach ($keys as $key) {
+ $results[$key] = $commit_data;
+ }
+ }
+
+ yield $this->yieldMap($results);
+ }
+
+}
diff --git a/src/query/ArcanistGitCommitMessageHardpointQuery.php b/src/query/ArcanistGitCommitMessageHardpointQuery.php
new file mode 100644
--- /dev/null
+++ b/src/query/ArcanistGitCommitMessageHardpointQuery.php
@@ -0,0 +1,53 @@
+<?php
+
+final class ArcanistGitCommitMessageHardpointQuery
+ extends ArcanistWorkflowHardpointQuery {
+
+ public function getHardpoints() {
+ return array(
+ ArcanistCommitRefPro::HARDPOINT_MESSAGE,
+ );
+ }
+
+ protected function canLoadRef(ArcanistRefPro $ref) {
+ return ($ref instanceof ArcanistCommitRefPro);
+ }
+
+ protected function canLoadHardpoint() {
+ $api = $this->getRepositoryAPI();
+ return ($api instanceof ArcanistGitAPI);
+ }
+
+ public function loadHardpoint(array $refs, $hardpoint) {
+ $api = $this->getRepositoryAPI();
+
+ $hashes = mpull($refs, 'getCommitHash');
+ $unique_hashes = array_fuse($hashes);
+
+ // TODO: Update this to use "%B", see T5028. We can also bulk-resolve
+ // these with "git show --quiet --format=... hash hash hash ... --".
+
+ $futures = array();
+ foreach ($unique_hashes as $hash) {
+ $futures[$hash] = $api->execFutureLocal(
+ 'log -n1 --format=%s %s --',
+ '%s%n%n%b',
+ $hash);
+ }
+
+ yield $this->yieldFutures($futures);
+
+ $messages = array();
+ foreach ($futures as $hash => $future) {
+ list($stdout) = $future->resolvex();
+ $messages[$hash] = $stdout;
+ }
+
+ foreach ($hashes as $ref_key => $hash) {
+ $hashes[$ref_key] = $messages[$hash];
+ }
+
+ yield $this->yieldMap($hashes);
+ }
+
+}
diff --git a/src/query/ArcanistWorkingCopyCommitHardpointQuery.php b/src/query/ArcanistWorkingCopyCommitHardpointQuery.php
new file mode 100644
--- /dev/null
+++ b/src/query/ArcanistWorkingCopyCommitHardpointQuery.php
@@ -0,0 +1,39 @@
+<?php
+
+final class ArcanistWorkingCopyCommitHardpointQuery
+ extends ArcanistWorkflowHardpointQuery {
+
+ public function getHardpoints() {
+ return array(
+ ArcanistWorkingCopyStateRefPro::HARDPOINT_COMMITREF,
+ );
+ }
+
+ protected function canLoadRef(ArcanistRefPro $ref) {
+ return ($ref instanceof ArcanistWorkingCopyStateRefPro);
+ }
+
+ public function loadHardpoint(array $refs, $hardpoint) {
+ yield $this->yieldRequests(
+ $refs,
+ array(
+ ArcanistWorkingCopyStateRefPro::HARDPOINT_BRANCHREF,
+ ));
+
+ $branch_refs = mpull($refs, 'getBranchRef');
+
+ yield $this->yieldRequests(
+ $branch_refs,
+ array(
+ ArcanistBranchRefPro::HARDPOINT_COMMITREF,
+ ));
+
+ $results = array();
+ foreach ($refs as $key => $ref) {
+ $results[$key] = $ref->getBranchRef()->getCommitRef();
+ }
+
+ yield $this->yieldMap($results);
+ }
+
+}
diff --git a/src/ref/ArcanistBranchRefPro.php b/src/ref/ArcanistBranchRefPro.php
new file mode 100644
--- /dev/null
+++ b/src/ref/ArcanistBranchRefPro.php
@@ -0,0 +1,57 @@
+<?php
+
+final class ArcanistBranchRefPro
+ extends ArcanistRefPro {
+
+ const HARDPOINT_COMMITREF = 'commitRef';
+
+ private $branchName;
+ private $refName;
+ private $isCurrentBranch;
+
+ public function getRefDisplayName() {
+ return pht('Branch %s', $this->getBranchName());
+ }
+
+ protected function newHardpoints() {
+ return array(
+ $this->newHardpoint(self::HARDPOINT_COMMITREF),
+ );
+ }
+
+ public function setBranchName($branch_name) {
+ $this->branchName = $branch_name;
+ return $this;
+ }
+
+ public function getBranchName() {
+ return $this->branchName;
+ }
+
+ public function setRefName($ref_name) {
+ $this->refName = $ref_name;
+ return $this;
+ }
+
+ public function getRefName() {
+ return $this->refName;
+ }
+
+ public function setIsCurrentBranch($is_current_branch) {
+ $this->isCurrentBranch = $is_current_branch;
+ return $this;
+ }
+
+ public function getIsCurrentBranch() {
+ return $this->isCurrentBranch;
+ }
+
+ public function attachCommitRef(ArcanistCommitRef $ref) {
+ return $this->attachHardpoint(self::HARDPOINT_COMMITREF, $ref);
+ }
+
+ public function getCommitRef() {
+ return $this->getHardpoint(self::HARDPOINT_COMMITREF);
+ }
+
+}
diff --git a/src/ref/ArcanistCommitRefPro.php b/src/ref/ArcanistCommitRefPro.php
new file mode 100644
--- /dev/null
+++ b/src/ref/ArcanistCommitRefPro.php
@@ -0,0 +1,93 @@
+<?php
+
+final class ArcanistCommitRefPro
+ extends ArcanistRefPro {
+
+ private $commitHash;
+ private $treeHash;
+ private $commitEpoch;
+ private $authorEpoch;
+ private $upstream;
+
+ const HARDPOINT_MESSAGE = 'message';
+ const HARDPOINT_UPSTREAM = 'upstream';
+
+ public function getRefDisplayName() {
+ return pht('Commit "%s"', $this->getCommitHash());
+ }
+
+ protected function newHardpoints() {
+ return array(
+ $this->newHardpoint(self::HARDPOINT_MESSAGE),
+ $this->newHardpoint(self::HARDPOINT_UPSTREAM),
+ );
+ }
+
+ public function setCommitHash($commit_hash) {
+ $this->commitHash = $commit_hash;
+ return $this;
+ }
+
+ public function getCommitHash() {
+ return $this->commitHash;
+ }
+
+ public function setTreeHash($tree_hash) {
+ $this->treeHash = $tree_hash;
+ return $this;
+ }
+
+ public function getTreeHash() {
+ return $this->treeHash;
+ }
+
+ public function setCommitEpoch($commit_epoch) {
+ $this->commitEpoch = $commit_epoch;
+ return $this;
+ }
+
+ public function getCommitEpoch() {
+ return $this->commitEpoch;
+ }
+
+ public function setAuthorEpoch($author_epoch) {
+ $this->authorEpoch = $author_epoch;
+ return $this;
+ }
+
+ public function getAuthorEpoch() {
+ return $this->authorEpoch;
+ }
+
+ public function getSummary() {
+ $message = $this->getMessage();
+
+ $message = trim($message);
+ $lines = phutil_split_lines($message, false);
+
+ return head($lines);
+ }
+
+ public function attachMessage($message) {
+ return $this->attachHardpoint(self::HARDPOINT_MESSAGE, $message);
+ }
+
+ public function getMessage() {
+ return $this->getHardpoint(self::HARDPOINT_MESSAGE);
+ }
+
+ public function getURI() {
+ return $this->getUpstreamProperty('uri');
+ }
+
+ private function getUpstreamProperty($key, $default = null) {
+ $upstream = $this->getHardpoint(self::HARDPOINT_UPSTREAM);
+
+ if (!$upstream) {
+ return $default;
+ }
+
+ return idx($upstream, $key, $default);
+ }
+
+}
diff --git a/src/ref/ArcanistRefPro.php b/src/ref/ArcanistRefPro.php
new file mode 100644
--- /dev/null
+++ b/src/ref/ArcanistRefPro.php
@@ -0,0 +1,8 @@
+<?php
+
+abstract class ArcanistRefPro
+ extends ArcanistHardpointObject {
+
+ abstract public function getRefDisplayName();
+
+}
diff --git a/src/ref/ArcanistWorkingCopyStateRefPro.php b/src/ref/ArcanistWorkingCopyStateRefPro.php
new file mode 100644
--- /dev/null
+++ b/src/ref/ArcanistWorkingCopyStateRefPro.php
@@ -0,0 +1,62 @@
+<?php
+
+final class ArcanistWorkingCopyStateRefPro
+ extends ArcanistRefPro {
+
+ const HARDPOINT_COMMITREF = 'commitRef';
+ const HARDPOINT_BRANCHREF = 'branchRef';
+ const HARDPOINT_REVISIONREFS = 'revisionRefs';
+
+ public function getRefDisplayName() {
+ // TODO: This could check attached hardpoints and render something more
+ // insightful.
+ return pht('Working Copy State');
+ }
+
+ protected function newHardpoints() {
+ return array(
+ $this->newHardpoint(self::HARDPOINT_COMMITREF),
+ $this->newHardpoint(self::HARDPOINT_BRANCHREF),
+ $this->newVectorHardpoint(self::HARDPOINT_REVISIONREFS),
+ );
+ }
+
+ public function attachBranchRef(ArcanistBranchRef $branch_ref) {
+ return $this->attachHardpoint(self::HARDPOINT_BRANCHREF, $branch_ref);
+ }
+
+ public function getBranchRef() {
+ return $this->getHardpoint(self::HARDPOINT_BRANCHREF);
+ }
+
+ public function setCommitRef(ArcanistCommitRef $commit_ref) {
+ return $this->attachHardpoint(self::HARDPOINT_COMMITREF, $commit_ref);
+ }
+
+ public function getCommitRef() {
+ return $this->getHardpoint(self::HARDPOINT_COMMITREF);
+ }
+
+ public function getRevisionRefs() {
+ return $this->getHardpoint(self::HARDPOINT_REVISIONREFS);
+ }
+
+ public function getRevisionRef() {
+ if ($this->hasAmbiguousRevisionRefs()) {
+ throw new Exception(
+ pht('State has multiple ambiguous revisions refs.'));
+ }
+
+ $refs = $this->getRevisionRefs();
+ if ($refs) {
+ return head($refs);
+ }
+
+ return null;
+ }
+
+ public function hasAmbiguousRevisionRefs() {
+ return (count($this->getRevisionRefs()) > 1);
+ }
+
+}
diff --git a/src/repository/api/ArcanistFilesystemAPI.php b/src/repository/api/ArcanistFilesystemAPI.php
--- a/src/repository/api/ArcanistFilesystemAPI.php
+++ b/src/repository/api/ArcanistFilesystemAPI.php
@@ -82,7 +82,7 @@
}
public function getRemoteURI() {
- throw new PhutilMethodNotImplementedException();
+ return null;
}
public function supportsLocalCommits() {
@@ -90,7 +90,9 @@
}
protected function buildLocalFuture(array $argv) {
- throw new PhutilMethodNotImplementedException();
+ $future = newv('ExecFuture', $argv);
+ $future->setCWD($this->getPath());
+ return $future;
}
public function supportsCommitRanges() {
diff --git a/src/toolset/query/ArcanistWorkflowHardpointQuery.php b/src/toolset/query/ArcanistWorkflowHardpointQuery.php
new file mode 100644
--- /dev/null
+++ b/src/toolset/query/ArcanistWorkflowHardpointQuery.php
@@ -0,0 +1,88 @@
+<?php
+
+abstract class ArcanistWorkflowHardpointQuery
+ extends ArcanistHardpointQuery {
+
+ private $workflow;
+ private $canLoadHardpoint;
+
+ final public function setWorkflow(ArcanistWorkflow $workflow) {
+ $this->workflow = $workflow;
+ return $this;
+ }
+
+ final public function getWorkflow() {
+ return $this->workflow;
+ }
+
+ final public function getWorkingCopy() {
+ return $this->getWorkflow()->getWorkingCopy();
+ }
+
+ final public function getRepositoryAPI() {
+ return $this->getWorkingCopy()->getRepositoryAPI();
+ }
+
+ public static function getAllQueries() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->execute();
+ }
+
+ final public function canLoadObject(ArcanistHardpointObject $object) {
+ if ($this->canLoadHardpoint === null) {
+ $this->canLoadHardpoint = $this->canLoadHardpoint();
+ }
+
+ if (!$this->canLoadHardpoint) {
+ return false;
+ }
+
+ if (!$object instanceof ArcanistRefPro) {
+ return false;
+ }
+
+ return $this->canLoadRef($object);
+ }
+
+ protected function canLoadHardpoint() {
+ return true;
+ }
+
+ abstract protected function canLoadRef(ArcanistRefPro $ref);
+
+ final public function yieldConduit($method, array $parameters) {
+ $conduit_engine = $this->getWorkflow()
+ ->getConduitEngine();
+
+ $call_object = $conduit_engine->newCall($method, $parameters);
+ $call_future = $conduit_engine->newFuture($call_object);
+
+ return $this->yieldFuture($call_future);
+ }
+
+ final public function yieldRepositoryRef() {
+ $workflow = $this->getWorkflow();
+
+ // TODO: This is currently a blocking request, but should yield to the
+ // hardpoint engine in the future.
+
+ $repository_ref = $workflow->getRepositoryRef();
+ $ref_future = new ImmediateFuture($repository_ref);
+
+ return $this->yieldFuture($ref_future);
+ }
+
+ final public function yieldValue(array $refs, $value) {
+ assert_instances_of($refs, 'ArcanistRefPro');
+
+ $keys = array_keys($refs);
+ $map = array_fill_keys($keys, $value);
+ return $this->yieldMap($map);
+ }
+
+ final public function yieldMap(array $map) {
+ return new ArcanistHardpointTaskResult($map);
+ }
+
+}
diff --git a/src/workflow/ArcanistInspectWorkflow.php b/src/workflow/ArcanistInspectWorkflow.php
new file mode 100644
--- /dev/null
+++ b/src/workflow/ArcanistInspectWorkflow.php
@@ -0,0 +1,207 @@
+<?php
+
+final class ArcanistInspectWorkflow
+ extends ArcanistArcWorkflow {
+
+ public function getWorkflowName() {
+ return 'inspect';
+ }
+
+ public function getWorkflowInformation() {
+ $help = pht(<<<EOTEXT
+Inspect internal object properties.
+EOTEXT
+);
+
+ return $this->newWorkflowInformation()
+ ->setSynopsis(pht('Show internal object information.'))
+ ->addExample(pht('**inspect** [__options__] -- __object__'))
+ ->setHelp($help);
+ }
+
+ public function getWorkflowArguments() {
+ return array(
+ $this->newWorkflowArgument('all')
+ ->setHelp(pht('Load all object hardpoints.')),
+ $this->newWorkflowArgument('objects')
+ ->setWildcard(true),
+ );
+ }
+
+ public function runWorkflow() {
+ $is_all = $this->getArgument('all');
+ $objects = $this->getArgument('objects');
+
+ $inspectors = ArcanistRefInspector::getAllInspectors();
+
+ if (!$objects) {
+ echo tsprintf(
+ "%s\n\n",
+ pht('Choose an object to inspect:'));
+
+ foreach ($inspectors as $inspector) {
+ echo tsprintf(
+ " - %s\n",
+ $inspector->getInspectFunctionName());
+ }
+
+ echo tsprintf("\n");
+
+ return 0;
+ }
+
+ $all_refs = array();
+ $ref_lists = array();
+ foreach ($objects as $description) {
+ $matches = null;
+ if (!preg_match('/^(\w+)(?:\(([^)]+)\))?\z/', $description, $matches)) {
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Object specification "%s" is unknown, expected a specification '.
+ 'like "commit(HEAD)".'));
+ }
+
+ $function = $matches[1];
+
+ if (!isset($inspectors[$function])) {
+ ksort($inspectors);
+ throw new PhutilArgumentUsageException(
+ pht(
+ 'Unknown object type "%s", supported types are: %s.',
+ $function,
+ implode(', ', array_keys($inspectors))));
+ }
+
+ $inspector = $inspectors[$function];
+
+ if (isset($matches[2])) {
+ $arguments = array($matches[2]);
+ } else {
+ $arguments = array();
+ }
+
+ $ref = $inspector->newInspectRef($arguments);
+
+ $ref_lists[get_class($ref)][] = $ref;
+ $all_refs[] = $ref;
+ }
+
+ if ($is_all) {
+ 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);
+ }
+ }
+ }
+
+ $list = array();
+ foreach ($all_refs as $ref) {
+ $out = $this->describeRef($ref, 0);
+ $list[] = implode('', $out);
+ }
+ $list = implode("\n", $list);
+
+ echo tsprintf('%B', $list);
+
+ return 0;
+ }
+
+ private function describeRef(ArcanistRefPro $ref, $depth) {
+ $indent = str_repeat(' ', $depth);
+
+ $out = array();
+ $out[] = tsprintf(
+ "%s+ [%s] %s\n",
+ $indent,
+ get_class($ref),
+ $ref->getRefDisplayName());
+
+ $hardpoint_list = $ref->getHardpointList();
+ foreach ($hardpoint_list->getHardpoints() as $hardpoint) {
+ $lines = $this->describeHardpoint($ref, $hardpoint, $depth + 1);
+ foreach ($lines as $line) {
+ $out[] = $line;
+ }
+ }
+
+ return $out;
+ }
+
+ private function describeHardpoint(
+ ArcanistRefPro $ref,
+ ArcanistHardpoint $hardpoint,
+ $depth) {
+ $indent = str_repeat(' ', $depth);
+
+ $children = array();
+ $values = array();
+
+ $hardpoint_key = $hardpoint->getHardpointKey();
+ if ($ref->hasAttachedHardpoint($hardpoint_key)) {
+ $mode = '*';
+ $value = $ref->getHardpoint($hardpoint_key);
+ if ($value instanceof ArcanistRefPro) {
+ $children[] = $value;
+ } else {
+ $values[] = $value;
+ }
+ } else {
+ $mode = 'o';
+ }
+
+ $out = array();
+ $out[] = tsprintf(
+ "%s%s [%s] %s\n",
+ $indent,
+ $mode,
+ get_class($hardpoint),
+ $hardpoint->getHardpointKey());
+
+ foreach ($children as $child) {
+ $lines = $this->describeRef($child, $depth + 1);
+ foreach ($lines as $line) {
+ $out[] = $line;
+ }
+ }
+
+ foreach ($values as $value) {
+ $lines = $this->describeValue($value, $depth + 1);
+ foreach ($lines as $line) {
+ $out[] = $line;
+ }
+ }
+
+ return $out;
+ }
+
+ private function describeValue($value, $depth) {
+ $indent = str_repeat(' ', $depth);
+
+ if (is_string($value)) {
+ $display_value = '"'.addcslashes(substr($value, 0, 64), "\n\r\t\\\"").'"';
+ } else if (is_scalar($value)) {
+ $display_value = phutil_string_cast($value);
+ } else if ($value === null) {
+ $display_value = 'null';
+ } else {
+ $display_value = phutil_describe_type($value);
+ }
+
+ $out = array();
+ $out[] = tsprintf(
+ "%s> %s\n",
+ $indent,
+ $display_value);
+ return $out;
+ }
+
+}
diff --git a/src/workflow/ArcanistWorkflow.php b/src/workflow/ArcanistWorkflow.php
--- a/src/workflow/ArcanistWorkflow.php
+++ b/src/workflow/ArcanistWorkflow.php
@@ -76,6 +76,8 @@
private $configurationEngine;
private $configurationSourceList;
+ private $hardpointEngine;
+
final public function setToolset(ArcanistToolset $toolset) {
$this->toolset = $toolset;
return $this;
@@ -2329,4 +2331,40 @@
->setExecutableFuture($future);
}
+ final protected function loadHardpoints(
+ array $objects,
+ array $requests) {
+
+ $engine = $this->getHardpointEngine();
+
+ $requests = $engine->requestHardpoints(
+ $objects,
+ $requests);
+
+ // TODO: Wait for only the required requests.
+ $engine->waitForRequests(array());
+ }
+
+ private function getHardpointEngine() {
+ if ($this->hardpointEngine === null) {
+ $this->hardpointEngine = $this->newHardpointEngine();
+ }
+ return $this->hardpointEngine;
+ }
+
+ private function newHardpointEngine() {
+ $engine = new ArcanistHardpointEngine();
+
+ $queries = ArcanistWorkflowHardpointQuery::getAllQueries();
+
+ foreach ($queries as $key => $query) {
+ $queries[$key] = id(clone $query)
+ ->setWorkflow($this);
+ }
+
+ $engine->setQueries($queries);
+
+ return $engine;
+ }
+
}
diff --git a/src/workingcopy/ArcanistFilesystemWorkingCopy.php b/src/workingcopy/ArcanistFilesystemWorkingCopy.php
--- a/src/workingcopy/ArcanistFilesystemWorkingCopy.php
+++ b/src/workingcopy/ArcanistFilesystemWorkingCopy.php
@@ -14,7 +14,7 @@
}
protected function newRepositoryAPI() {
- return new ArcanistFilesystemAPI();
+ return new ArcanistFilesystemAPI($this->getPath());
}
public function getProjectConfigurationFilePath() {
diff --git a/src/workingcopy/ArcanistWorkingCopy.php b/src/workingcopy/ArcanistWorkingCopy.php
--- a/src/workingcopy/ArcanistWorkingCopy.php
+++ b/src/workingcopy/ArcanistWorkingCopy.php
@@ -57,7 +57,7 @@
$working_copy = new ArcanistFilesystemWorkingCopy();
- self::configureWorkingCopy($working_copy, $ancestor_path, $path);
+ self::configureWorkingCopy($working_copy, $path, $path);
return $working_copy;
}

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 22, 9:54 PM (18 h, 8 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6776089
Default Alt Text
D21078.diff (33 KB)

Event Timeline