1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-25 16:22:42 +01:00

Introduce "arc inspect" and some of the new ref/hardpoint classes

Summary:
Ref T11968. Inches toward the new ref/hardpoint code by introducing the modern refs as "RefPro" objects and supporting an "arc inspect <object>" to load objects and hardpoints.

This doesn't impact any existing runtime behavior.

Test Plan: Ran "arc inspect [--all] commit(...)", got hardpoint queries and yield-based data fetching.

Maniphest Tasks: T11968

Differential Revision: https://secure.phabricator.com/D21078
This commit is contained in:
epriestley 2020-04-08 12:52:41 -07:00
parent 92b29f53f3
commit adea2550f5
19 changed files with 803 additions and 12 deletions

View file

@ -54,6 +54,7 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'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 @@ phutil_register_library_map(array(
'ArcanistBraceFormattingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistBraceFormattingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistBranchRef' => 'ArcanistRef',
'ArcanistBranchRefPro' => 'ArcanistRefPro',
'ArcanistBranchWorkflow' => 'ArcanistFeatureWorkflow',
'ArcanistBrowseCommitHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistBrowseCommitURIHardpointLoader' => 'ArcanistBrowseURIHardpointLoader',
@ -1058,7 +1071,10 @@ phutil_register_library_map(array(
'ArcanistCommentStyleXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistCommentStyleXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistCommitRef' => 'ArcanistRef',
'ArcanistCommitRefInspector' => 'ArcanistRefInspector',
'ArcanistCommitRefPro' => 'ArcanistRefPro',
'ArcanistCommitUpstreamHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistCommitUpstreamHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
'ArcanistCommitWorkflow' => 'ArcanistWorkflow',
'ArcanistCompilerLintRenderer' => 'ArcanistLintRenderer',
'ArcanistComposerLinter' => 'ArcanistLinter',
@ -1159,6 +1175,7 @@ phutil_register_library_map(array(
'ArcanistGetConfigWorkflow' => 'ArcanistWorkflow',
'ArcanistGitAPI' => 'ArcanistRepositoryAPI',
'ArcanistGitCommitMessageHardpointLoader' => 'ArcanistGitHardpointLoader',
'ArcanistGitCommitMessageHardpointQuery' => 'ArcanistWorkflowHardpointQuery',
'ArcanistGitHardpointLoader' => 'ArcanistHardpointLoader',
'ArcanistGitLandEngine' => 'ArcanistLandEngine',
'ArcanistGitRevisionHardpointLoader' => 'ArcanistGitHardpointLoader',
@ -1182,6 +1199,7 @@ phutil_register_library_map(array(
'ArcanistHardpointRequest' => 'Phobject',
'ArcanistHardpointRequestList' => 'Phobject',
'ArcanistHardpointTask' => 'Phobject',
'ArcanistHardpointTaskResult' => 'Phobject',
'ArcanistHelpWorkflow' => 'ArcanistWorkflow',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistHexadecimalNumericScalarCasingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@ -1201,6 +1219,7 @@ phutil_register_library_map(array(
'ArcanistInlineHTMLXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInnerFunctionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInnerFunctionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistInspectWorkflow' => 'ArcanistArcWorkflow',
'ArcanistInstallCertificateWorkflow' => 'ArcanistWorkflow',
'ArcanistInstanceOfOperatorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistInstanceofOperatorXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@ -1337,6 +1356,8 @@ phutil_register_library_map(array(
'ArcanistRaggedClassTreeEdgeXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistRaggedClassTreeEdgeXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistRef' => 'Phobject',
'ArcanistRefInspector' => 'Phobject',
'ArcanistRefPro' => 'ArcanistHardpointObject',
'ArcanistRefQuery' => 'Phobject',
'ArcanistRepositoryAPI' => 'Phobject',
'ArcanistRepositoryAPIMiscTestCase' => 'PhutilTestCase',
@ -1444,12 +1465,15 @@ phutil_register_library_map(array(
'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',

View file

@ -46,6 +46,10 @@ final class ArcanistHardpointList
return isset($this->attached[$hardpoint]);
}
public function getHardpoints() {
return $this->hardpoints;
}
public function getHardpointDefinition($object, $hardpoint) {
if (!$this->hasHardpoint($object, $hardpoint)) {
throw new Exception(

View file

@ -100,6 +100,7 @@ final class ArcanistHardpointTask
$generator->next();
}
$generator_result = null;
if ($generator->valid()) {
$result = $generator->current();
@ -152,17 +153,25 @@ final class ArcanistHardpointTask
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);

View file

@ -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;
}
}

View file

@ -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]);
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -0,0 +1,8 @@
<?php
abstract class ArcanistRefPro
extends ArcanistHardpointObject {
abstract public function getRefDisplayName();
}

View file

@ -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);
}
}

View file

@ -82,7 +82,7 @@ final class ArcanistFilesystemAPI
}
public function getRemoteURI() {
throw new PhutilMethodNotImplementedException();
return null;
}
public function supportsLocalCommits() {
@ -90,7 +90,9 @@ final class ArcanistFilesystemAPI
}
protected function buildLocalFuture(array $argv) {
throw new PhutilMethodNotImplementedException();
$future = newv('ExecFuture', $argv);
$future->setCWD($this->getPath());
return $future;
}
public function supportsCommitRanges() {

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -76,6 +76,8 @@ abstract class ArcanistWorkflow extends Phobject {
private $configurationEngine;
private $configurationSourceList;
private $hardpointEngine;
final public function setToolset(ArcanistToolset $toolset) {
$this->toolset = $toolset;
return $this;
@ -2329,4 +2331,40 @@ abstract class ArcanistWorkflow extends Phobject {
->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;
}
}

View file

@ -14,7 +14,7 @@ final class ArcanistFilesystemWorkingCopy
}
protected function newRepositoryAPI() {
return new ArcanistFilesystemAPI();
return new ArcanistFilesystemAPI($this->getPath());
}
public function getProjectConfigurationFilePath() {

View file

@ -57,7 +57,7 @@ abstract class ArcanistWorkingCopy
$working_copy = new ArcanistFilesystemWorkingCopy();
self::configureWorkingCopy($working_copy, $ancestor_path, $path);
self::configureWorkingCopy($working_copy, $path, $path);
return $working_copy;
}