1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-11-22 14:52:40 +01:00

Update "arc paste" for Toolsets

Summary: Ref T13490. More-or-less straightforward upgrade to modern calls.

Test Plan: Created and viewed pastes.

Maniphest Tasks: T13490

Differential Revision: https://secure.phabricator.com/D21104
This commit is contained in:
epriestley 2020-04-13 12:34:34 -07:00
parent c8dd2a3753
commit d408a80ae1
22 changed files with 539 additions and 273 deletions

View file

@ -189,9 +189,7 @@ phutil_register_library_map(array(
'ArcanistFileConfigurationSource' => 'config/source/ArcanistFileConfigurationSource.php', 'ArcanistFileConfigurationSource' => 'config/source/ArcanistFileConfigurationSource.php',
'ArcanistFileDataRef' => 'upload/ArcanistFileDataRef.php', 'ArcanistFileDataRef' => 'upload/ArcanistFileDataRef.php',
'ArcanistFileRef' => 'ref/file/ArcanistFileRef.php', 'ArcanistFileRef' => 'ref/file/ArcanistFileRef.php',
'ArcanistFileSymbolHardpointQuery' => 'ref/file/ArcanistFileSymbolHardpointQuery.php',
'ArcanistFileSymbolRef' => 'ref/file/ArcanistFileSymbolRef.php', 'ArcanistFileSymbolRef' => 'ref/file/ArcanistFileSymbolRef.php',
'ArcanistFileSymbolRefInspector' => 'ref/file/ArcanistFileSymbolRefInspector.php',
'ArcanistFileUploader' => 'upload/ArcanistFileUploader.php', 'ArcanistFileUploader' => 'upload/ArcanistFileUploader.php',
'ArcanistFilenameLinter' => 'lint/linter/ArcanistFilenameLinter.php', 'ArcanistFilenameLinter' => 'lint/linter/ArcanistFilenameLinter.php',
'ArcanistFilenameLinterTestCase' => 'lint/linter/__tests__/ArcanistFilenameLinterTestCase.php', 'ArcanistFilenameLinterTestCase' => 'lint/linter/__tests__/ArcanistFilenameLinterTestCase.php',
@ -361,6 +359,8 @@ phutil_register_library_map(array(
'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParenthesesSpacingXHPASTLinterRuleTestCase.php', 'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParenthesesSpacingXHPASTLinterRuleTestCase.php',
'ArcanistParseStrUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParseStrUseXHPASTLinterRule.php', 'ArcanistParseStrUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParseStrUseXHPASTLinterRule.php',
'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParseStrUseXHPASTLinterRuleTestCase.php', 'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParseStrUseXHPASTLinterRuleTestCase.php',
'ArcanistPasteRef' => 'ref/paste/ArcanistPasteRef.php',
'ArcanistPasteSymbolRef' => 'ref/paste/ArcanistPasteSymbolRef.php',
'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php', 'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php',
'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php', 'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php',
'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php', 'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php',
@ -401,9 +401,7 @@ phutil_register_library_map(array(
'ArcanistRevisionCommitMessageHardpointQuery' => 'ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php', 'ArcanistRevisionCommitMessageHardpointQuery' => 'ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php',
'ArcanistRevisionRef' => 'ref/revision/ArcanistRevisionRef.php', 'ArcanistRevisionRef' => 'ref/revision/ArcanistRevisionRef.php',
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php', 'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
'ArcanistRevisionSymbolHardpointQuery' => 'ref/revision/ArcanistRevisionSymbolHardpointQuery.php',
'ArcanistRevisionSymbolRef' => 'ref/revision/ArcanistRevisionSymbolRef.php', 'ArcanistRevisionSymbolRef' => 'ref/revision/ArcanistRevisionSymbolRef.php',
'ArcanistRevisionSymbolRefInspector' => 'ref/revision/ArcanistRevisionSymbolRefInspector.php',
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php', 'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php', 'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php', 'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
@ -424,6 +422,9 @@ phutil_register_library_map(array(
'ArcanistSetting' => 'configuration/ArcanistSetting.php', 'ArcanistSetting' => 'configuration/ArcanistSetting.php',
'ArcanistSettings' => 'configuration/ArcanistSettings.php', 'ArcanistSettings' => 'configuration/ArcanistSettings.php',
'ArcanistShellCompleteWorkflow' => 'toolset/workflow/ArcanistShellCompleteWorkflow.php', 'ArcanistShellCompleteWorkflow' => 'toolset/workflow/ArcanistShellCompleteWorkflow.php',
'ArcanistSimpleSymbolHardpointQuery' => 'ref/simple/ArcanistSimpleSymbolHardpointQuery.php',
'ArcanistSimpleSymbolRef' => 'ref/simple/ArcanistSimpleSymbolRef.php',
'ArcanistSimpleSymbolRefInspector' => 'ref/simple/ArcanistSimpleSymbolRefInspector.php',
'ArcanistSingleLintEngine' => 'lint/engine/ArcanistSingleLintEngine.php', 'ArcanistSingleLintEngine' => 'lint/engine/ArcanistSingleLintEngine.php',
'ArcanistSlownessXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSlownessXHPASTLinterRule.php', 'ArcanistSlownessXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSlownessXHPASTLinterRule.php',
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSlownessXHPASTLinterRuleTestCase.php', 'ArcanistSlownessXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSlownessXHPASTLinterRuleTestCase.php',
@ -439,6 +440,8 @@ phutil_register_library_map(array(
'ArcanistSymbolRef' => 'ref/symbol/ArcanistSymbolRef.php', 'ArcanistSymbolRef' => 'ref/symbol/ArcanistSymbolRef.php',
'ArcanistSyntaxErrorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSyntaxErrorXHPASTLinterRule.php', 'ArcanistSyntaxErrorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSyntaxErrorXHPASTLinterRule.php',
'ArcanistSystemConfigurationSource' => 'config/source/ArcanistSystemConfigurationSource.php', 'ArcanistSystemConfigurationSource' => 'config/source/ArcanistSystemConfigurationSource.php',
'ArcanistTaskRef' => 'ref/task/ArcanistTaskRef.php',
'ArcanistTaskSymbolRef' => 'ref/task/ArcanistTaskSymbolRef.php',
'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php', 'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php',
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTautologicalExpressionXHPASTLinterRule.php', 'ArcanistTautologicalExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTautologicalExpressionXHPASTLinterRule.php',
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTautologicalExpressionXHPASTLinterRuleTestCase.php', 'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTautologicalExpressionXHPASTLinterRuleTestCase.php',
@ -1171,9 +1174,7 @@ phutil_register_library_map(array(
'ArcanistRef', 'ArcanistRef',
'ArcanistDisplayRefInterface', 'ArcanistDisplayRefInterface',
), ),
'ArcanistFileSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery', 'ArcanistFileSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistFileSymbolRef' => 'ArcanistSymbolRef',
'ArcanistFileSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistFileUploader' => 'Phobject', 'ArcanistFileUploader' => 'Phobject',
'ArcanistFilenameLinter' => 'ArcanistLinter', 'ArcanistFilenameLinter' => 'ArcanistLinter',
'ArcanistFilenameLinterTestCase' => 'ArcanistLinterTestCase', 'ArcanistFilenameLinterTestCase' => 'ArcanistLinterTestCase',
@ -1343,7 +1344,12 @@ phutil_register_library_map(array(
'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistParseStrUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistParseStrUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPasteWorkflow' => 'ArcanistWorkflow', 'ArcanistPasteRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistPasteSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistPasteWorkflow' => 'ArcanistArcWorkflow',
'ArcanistPatchWorkflow' => 'ArcanistWorkflow', 'ArcanistPatchWorkflow' => 'ArcanistWorkflow',
'ArcanistPhpLinter' => 'ArcanistExternalLinter', 'ArcanistPhpLinter' => 'ArcanistExternalLinter',
'ArcanistPhpLinterTestCase' => 'ArcanistExternalLinterTestCase', 'ArcanistPhpLinterTestCase' => 'ArcanistExternalLinterTestCase',
@ -1386,9 +1392,7 @@ phutil_register_library_map(array(
'ArcanistDisplayRefInterface', 'ArcanistDisplayRefInterface',
), ),
'ArcanistRevisionRefSource' => 'Phobject', 'ArcanistRevisionRefSource' => 'Phobject',
'ArcanistRevisionSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery', 'ArcanistRevisionSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistRevisionSymbolRef' => 'ArcanistSymbolRef',
'ArcanistRevisionSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter', 'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase', 'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRubyLinter' => 'ArcanistExternalLinter', 'ArcanistRubyLinter' => 'ArcanistExternalLinter',
@ -1408,6 +1412,9 @@ phutil_register_library_map(array(
'ArcanistSetting' => 'Phobject', 'ArcanistSetting' => 'Phobject',
'ArcanistSettings' => 'Phobject', 'ArcanistSettings' => 'Phobject',
'ArcanistShellCompleteWorkflow' => 'ArcanistWorkflow', 'ArcanistShellCompleteWorkflow' => 'ArcanistWorkflow',
'ArcanistSimpleSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistSimpleSymbolRef' => 'ArcanistSymbolRef',
'ArcanistSimpleSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistSingleLintEngine' => 'ArcanistLintEngine', 'ArcanistSingleLintEngine' => 'ArcanistLintEngine',
'ArcanistSlownessXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistSlownessXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistSlownessXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@ -1423,6 +1430,11 @@ phutil_register_library_map(array(
'ArcanistSymbolRef' => 'ArcanistRef', 'ArcanistSymbolRef' => 'ArcanistRef',
'ArcanistSyntaxErrorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistSyntaxErrorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSystemConfigurationSource' => 'ArcanistFilesystemConfigurationSource', 'ArcanistSystemConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistTaskRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistTaskSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistTasksWorkflow' => 'ArcanistWorkflow', 'ArcanistTasksWorkflow' => 'ArcanistWorkflow',
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule', 'ArcanistTautologicalExpressionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase', 'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',

View file

@ -6,6 +6,7 @@ final class ConduitSearchFuture
private $conduitEngine; private $conduitEngine;
private $method; private $method;
private $constraints; private $constraints;
private $attachments;
private $objects = array(); private $objects = array();
private $cursor; private $cursor;
@ -28,7 +29,7 @@ final class ConduitSearchFuture
return $this->method; return $this->method;
} }
public function setConstraints($constraints) { public function setConstraints(array $constraints) {
$this->constraints = $constraints; $this->constraints = $constraints;
return $this; return $this;
} }
@ -37,6 +38,15 @@ final class ConduitSearchFuture
return $this->constraints; return $this->constraints;
} }
public function setAttachments(array $attachments) {
$this->attachments = $attachments;
return $this;
}
public function getAttachments() {
return $this->attachments;
}
public function isReady() { public function isReady() {
if ($this->hasResult()) { if ($this->hasResult()) {
return true; return true;
@ -86,6 +96,10 @@ final class ConduitSearchFuture
'constraints' => $constraints, 'constraints' => $constraints,
); );
if ($this->attachments) {
$parameters['attachments'] = $this->attachments;
}
if ($this->cursor !== null) { if ($this->cursor !== null) {
$parameters['after'] = (string)$this->cursor; $parameters['after'] = (string)$this->cursor;
} }

View file

@ -6,11 +6,24 @@ abstract class ArcanistRefInspector
abstract public function getInspectFunctionName(); abstract public function getInspectFunctionName();
abstract public function newInspectRef(array $argv); abstract public function newInspectRef(array $argv);
protected function newInspectors() {
return array($this);
}
final public static function getAllInspectors() { final public static function getAllInspectors() {
return id(new PhutilClassMapQuery()) $base_inspectors = id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__) ->setAncestorClass(__CLASS__)
->setUniqueMethod('getInspectFunctionName')
->execute(); ->execute();
$results = array();
foreach ($base_inspectors as $base_inspector) {
foreach ($base_inspector->newInspectors() as $inspector) {
$results[] = $inspector;
}
}
return mpull($results, null, 'getInspectFunctionName');
} }
} }

View file

@ -92,4 +92,14 @@ final class ArcanistLogEngine
->setMessage($message)); ->setMessage($message));
} }
public function writeWaitingForInput() {
if (!phutil_is_interactive()) {
return;
}
$this->writeStatus(
pht('INPUT'),
pht('Waiting for input on stdin...'));
}
} }

View file

@ -6,6 +6,7 @@ final class ArcanistDisplayRef
ArcanistTerminalStringInterface { ArcanistTerminalStringInterface {
private $ref; private $ref;
private $uri;
public function setRef(ArcanistRef $ref) { public function setRef(ArcanistRef $ref) {
$this->ref = $ref; $this->ref = $ref;
@ -16,6 +17,15 @@ final class ArcanistDisplayRef
return $this->ref; return $this->ref;
} }
public function setURI($uri) {
$this->uri = $uri;
return $this;
}
public function getURI() {
return $this->uri;
}
public function newTerminalString() { public function newTerminalString() {
$ref = $this->getRef(); $ref = $this->getRef();
@ -60,9 +70,20 @@ final class ArcanistDisplayRef
} }
$ref = $this->getRef(); $ref = $this->getRef();
return tsprintf( $output = array();
$output[] = tsprintf(
"<bg:cyan>** * **</bg> %s\n", "<bg:cyan>** * **</bg> %s\n",
$display_text); $display_text);
$uri = $this->getURI();
if ($uri !== null) {
$output[] = tsprintf(
"<bg:cyan>** :// **</bg> __%s__\n",
$uri);
}
return $output;
} }
} }

View file

@ -1,47 +1,30 @@
<?php <?php
final class ArcanistFileSymbolRef final class ArcanistFileSymbolRef
extends ArcanistSymbolRef { extends ArcanistSimpleSymbolRef {
private $type;
const TYPE_ID = 'id';
const TYPE_PHID = 'phid';
public function getRefDisplayName() { public function getRefDisplayName() {
return pht('File Symbol "%s"', $this->getSymbol()); return pht('File Symbol "%s"', $this->getSymbol());
} }
protected function newCacheKeyParts() { protected function getSimpleSymbolPrefixPattern() {
return array( return '[Ff]?';
sprintf('type(%s)', $this->type),
);
} }
public function getSymbolType() { protected function getSimpleSymbolPHIDType() {
return $this->type; return 'FILE';
} }
protected function resolveSymbol($symbol) { public function getSimpleSymbolConduitSearchMethodName() {
$matches = null; return 'file.search';
}
$is_id = preg_match('/^[Ff]?([1-9]\d*)\z/', $symbol, $matches); public function getSimpleSymbolInspectFunctionName() {
if ($is_id) { return 'file';
$this->type = self::TYPE_ID; }
return (int)$matches[1];
}
$is_phid = preg_match('/^PHID-FILE-\S+\z/', $symbol, $matches); public function newSimpleSymbolObjectRef() {
if ($is_phid) { return new ArcanistFileRef();
$this->type = self::TYPE_PHID;
return $matches[0];
}
throw new PhutilArgumentUsageException(
pht(
'The format of file symbol "%s" is unrecognized. Expected a '.
'monogram like "F123", or an ID like "123", or a file PHID.',
$symbol));
} }
} }

View file

@ -1,22 +0,0 @@
<?php
final class ArcanistFileSymbolRefInspector
extends ArcanistRefInspector {
public function getInspectFunctionName() {
return 'file';
}
public function newInspectRef(array $argv) {
if (count($argv) !== 1) {
throw new PhutilArgumentUsageException(
pht(
'Expected exactly one argument to "file(...)" with a '.
'file symbol.'));
}
return id(new ArcanistFileSymbolRef())
->setSymbol($argv[0]);
}
}

View file

@ -0,0 +1,52 @@
<?php
final class ArcanistPasteRef
extends ArcanistRef
implements
ArcanistDisplayRefInterface {
private $parameters;
public function getRefDisplayName() {
return pht('Paste "%s"', $this->getMonogram());
}
public static function newFromConduit(array $parameters) {
$ref = new self();
$ref->parameters = $parameters;
return $ref;
}
public function getID() {
return idx($this->parameters, 'id');
}
public function getPHID() {
return idx($this->parameters, 'phid');
}
public function getTitle() {
return idxv($this->parameters, array('fields', 'title'));
}
public function getURI() {
return idxv($this->parameters, array('fields', 'uri'));
}
public function getContent() {
return idxv($this->parameters, array('attachments', 'content', 'content'));
}
public function getMonogram() {
return 'P'.$this->getID();
}
public function getDisplayRefObjectName() {
return $this->getMonogram();
}
public function getDisplayRefTitle() {
return $this->getTitle();
}
}

View file

@ -0,0 +1,36 @@
<?php
final class ArcanistPasteSymbolRef
extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() {
return pht('Paste Symbol "%s"', $this->getSymbol());
}
protected function getSimpleSymbolPrefixPattern() {
return '[Pp]?';
}
protected function getSimpleSymbolPHIDType() {
return 'PSTE';
}
public function getSimpleSymbolConduitSearchMethodName() {
return 'paste.search';
}
public function getSimpleSymbolConduitSearchAttachments() {
return array(
'content' => true,
);
}
public function getSimpleSymbolInspectFunctionName() {
return 'paste';
}
public function newSimpleSymbolObjectRef() {
return new ArcanistPasteRef();
}
}

View file

@ -1,40 +0,0 @@
<?php
final class ArcanistRevisionSymbolHardpointQuery
extends ArcanistRuntimeHardpointQuery {
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->yieldConduitSearch(
'differential.revision.search',
array(
'ids' => array_values($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);
}
}

View file

@ -1,25 +1,30 @@
<?php <?php
final class ArcanistRevisionSymbolRef final class ArcanistRevisionSymbolRef
extends ArcanistSymbolRef { extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() { public function getRefDisplayName() {
return pht('Revision Symbol "%s"', $this->getSymbol()); return pht('Revision Symbol "%s"', $this->getSymbol());
} }
protected function resolveSymbol($symbol) { protected function getSimpleSymbolPrefixPattern() {
$matches = null; return '[Dd]?';
}
if (!preg_match('/^[Dd]?([1-9]\d*)\z/', $symbol, $matches)) { protected function getSimpleSymbolPHIDType() {
throw new PhutilArgumentUsageException( return 'DREV';
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]; public function getSimpleSymbolConduitSearchMethodName() {
return 'differential.revision.search';
}
public function getSimpleSymbolInspectFunctionName() {
return 'revision';
}
public function newSimpleSymbolObjectRef() {
return new ArcanistRevisionRef();
} }
} }

View file

@ -1,22 +0,0 @@
<?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]);
}
}

View file

@ -1,6 +1,6 @@
<?php <?php
final class ArcanistFileSymbolHardpointQuery final class ArcanistSimpleSymbolHardpointQuery
extends ArcanistRuntimeHardpointQuery { extends ArcanistRuntimeHardpointQuery {
public function getHardpoints() { public function getHardpoints() {
@ -10,7 +10,7 @@ final class ArcanistFileSymbolHardpointQuery
} }
protected function canLoadRef(ArcanistRef $ref) { protected function canLoadRef(ArcanistRef $ref) {
return ($ref instanceof ArcanistFileSymbolRef); return ($ref instanceof ArcanistSimpleSymbolRef);
} }
public function loadHardpoint(array $refs, $hardpoint) { public function loadHardpoint(array $refs, $hardpoint) {
@ -19,23 +19,31 @@ final class ArcanistFileSymbolHardpointQuery
foreach ($refs as $key => $ref) { foreach ($refs as $key => $ref) {
switch ($ref->getSymbolType()) { switch ($ref->getSymbolType()) {
case ArcanistFileSymbolRef::TYPE_ID: case ArcanistSimpleSymbolRef::TYPE_ID:
$id_map[$key] = $ref->getSymbol(); $id_map[$key] = $ref->getSymbol();
break; break;
case ArcanistFileSymbolRef::TYPE_PHID: case ArcanistSimpleSymbolRef::TYPE_PHID:
$phid_map[$key] = $ref->getSymbol(); $phid_map[$key] = $ref->getSymbol();
break; break;
} }
} }
$template_ref = head($refs);
$conduit_method =
$template_ref->getSimpleSymbolConduitSearchMethodName();
$conduit_attachments =
$template_ref->getSimpleSymbolConduitSearchAttachments();
$futures = array(); $futures = array();
if ($id_map) { if ($id_map) {
$id_future = $this->newConduitSearch( $id_future = $this->newConduitSearch(
'file.search', $conduit_method,
array( array(
'ids' => array_values(array_fuse($id_map)), 'ids' => array_values(array_fuse($id_map)),
)); ),
$conduit_attachments);
$futures[] = $id_future; $futures[] = $id_future;
} else { } else {
@ -44,10 +52,11 @@ final class ArcanistFileSymbolHardpointQuery
if ($phid_map) { if ($phid_map) {
$phid_future = $this->newConduitSearch( $phid_future = $this->newConduitSearch(
'file.search', $ref->getSimpleSymbolConduitSearchMethodName(),
array( array(
'phids' => array_values(array_fuse($phid_map)), 'phids' => array_values(array_fuse($phid_map)),
)); ),
$conduit_attachments);
$futures[] = $phid_future; $futures[] = $phid_future;
} else { } else {
@ -76,12 +85,16 @@ final class ArcanistFileSymbolHardpointQuery
} }
} }
$object_ref = $template_ref->newSimpleSymbolObjectRef();
foreach ($result_map as $key => $raw_result) { foreach ($result_map as $key => $raw_result) {
if ($raw_result === null) { if ($raw_result === null) {
continue; continue;
} }
$result_map[$key] = ArcanistFileRef::newFromConduit($raw_result); $result_map[$key] = call_user_func_array(
array(get_class($object_ref), 'newFromConduit'),
array($raw_result));
} }
yield $this->yieldMap($result_map); yield $this->yieldMap($result_map);

View file

@ -0,0 +1,58 @@
<?php
abstract class ArcanistSimpleSymbolRef
extends ArcanistSymbolRef {
private $type;
const TYPE_ID = 'id';
const TYPE_PHID = 'phid';
final protected function newCacheKeyParts() {
return array(
sprintf('type(%s)', $this->type),
);
}
final public function getSymbolType() {
return $this->type;
}
final protected function resolveSymbol($symbol) {
$matches = null;
$prefix_pattern = $this->getSimpleSymbolPrefixPattern();
$id_pattern = '(^'.$prefix_pattern.'([1-9]\d*)\z)';
$is_id = preg_match($id_pattern, $symbol, $matches);
if ($is_id) {
$this->type = self::TYPE_ID;
return (int)$matches[1];
}
$phid_type = $this->getSimpleSymbolPHIDType();
$phid_type = preg_quote($phid_type);
$phid_pattern = '(^PHID-'.$phid_type.'-\S+\z)';
$is_phid = preg_match($phid_pattern, $symbol, $matches);
if ($is_phid) {
$this->type = self::TYPE_PHID;
return $matches[0];
}
throw new PhutilArgumentUsageException(
pht(
'The format of symbol "%s" is unrecognized. Expected a '.
'monogram like "X123", or an ID like "123", or a PHID.',
$symbol));
}
abstract protected function getSimpleSymbolPrefixPattern();
abstract protected function getSimpleSymbolPHIDType();
abstract public function getSimpleSymbolConduitSearchMethodName();
abstract public function getSimpleSymbolInspectFunctionName();
public function getSimpleSymbolConduitSearchAttachments() {
return array();
}
}

View file

@ -0,0 +1,47 @@
<?php
final class ArcanistSimpleSymbolRefInspector
extends ArcanistRefInspector {
private $templateRef;
protected function newInspectors() {
$refs = id(new PhutilClassMapQuery())
->setAncestorClass('ArcanistSimpleSymbolRef')
->execute();
$inspectors = array();
foreach ($refs as $ref) {
$inspectors[] = id(new self())
->setTemplateRef($ref);
}
return $inspectors;
}
public function setTemplateRef(ArcanistSimpleSymbolRef $template_ref) {
$this->templateRef = $template_ref;
return $this;
}
public function getTemplateRef() {
return $this->templateRef;
}
public function getInspectFunctionName() {
return $this->getTemplateRef()->getSimpleSymbolInspectFunctionName();
}
public function newInspectRef(array $argv) {
if (count($argv) !== 1) {
throw new PhutilArgumentUsageException(
pht(
'Expected exactly one argument to "%s(...)" with a symbol.',
$this->getInspectFunctionName()));
}
return id(clone $this->getTemplateRef())
->setSymbol($argv[0]);
}
}

View file

@ -59,6 +59,17 @@ final class ArcanistSymbolEngine
$symbols); $symbols);
} }
public function loadPasteForSymbol($symbol) {
$refs = $this->loadPastesForSymbols(array($symbol));
return head($refs)->getObject();
}
public function loadPastesForSymbols(array $symbols) {
return $this->loadRefsForSymbols(
new ArcanistPasteSymbolRef(),
$symbols);
}
public function loadRefsForSymbols( public function loadRefsForSymbols(
ArcanistSymbolRef $template, ArcanistSymbolRef $template,
array $symbols) { array $symbols) {

View file

@ -0,0 +1,44 @@
<?php
final class ArcanistTaskRef
extends ArcanistRef
implements
ArcanistDisplayRefInterface {
private $parameters;
public function getRefDisplayName() {
return pht('Task "%s"', $this->getMonogram());
}
public static function newFromConduit(array $parameters) {
$ref = new self();
$ref->parameters = $parameters;
return $ref;
}
public function getID() {
return idx($this->parameters, 'id');
}
public function getPHID() {
return idx($this->parameters, 'phid');
}
public function getName() {
return idxv($this->parameters, array('fields', 'name'));
}
public function getMonogram() {
return 'T'.$this->getID();
}
public function getDisplayRefObjectName() {
return $this->getMonogram();
}
public function getDisplayRefTitle() {
return $this->getName();
}
}

View file

@ -0,0 +1,30 @@
<?php
final class ArcanistTaskSymbolRef
extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() {
return pht('Task Symbol "%s"', $this->getSymbol());
}
protected function getSimpleSymbolPrefixPattern() {
return '[Tt]?';
}
protected function getSimpleSymbolPHIDType() {
return 'TASK';
}
public function getSimpleSymbolConduitSearchMethodName() {
return 'maniphest.search';
}
public function getSimpleSymbolInspectFunctionName() {
return 'task';
}
public function newSimpleSymbolObjectRef() {
return new ArcanistTaskRef();
}
}

View file

@ -51,14 +51,19 @@ abstract class ArcanistRuntimeHardpointQuery
abstract protected function canLoadRef(ArcanistRef $ref); abstract protected function canLoadRef(ArcanistRef $ref);
final public function newConduitSearch($method, $constraints) { final public function newConduitSearch(
$method,
$constraints,
$attachments = array()) {
$conduit_engine = $this->getRuntime() $conduit_engine = $this->getRuntime()
->getConduitEngine(); ->getConduitEngine();
$conduit_future = id(new ConduitSearchFuture()) $conduit_future = id(new ConduitSearchFuture())
->setConduitEngine($conduit_engine) ->setConduitEngine($conduit_engine)
->setMethod($method) ->setMethod($method)
->setConstraints($constraints); ->setConstraints($constraints)
->setAttachments($attachments);
return $conduit_future; return $conduit_future;
} }

View file

@ -44,13 +44,7 @@ EOTEXT
} }
$method = head($method); $method = head($method);
if (phutil_is_interactive()) { $params = $this->readStdin();
echo tsprintf(
"%s\n",
pht('Waiting for JSON parameters on stdin...'));
}
$params = @file_get_contents('php://stdin');
try { try {
$params = phutil_json_decode($params); $params = phutil_json_decode($params);
} catch (PhutilJSONParserException $ex) { } catch (PhutilJSONParserException $ex) {

View file

@ -1,145 +1,137 @@
<?php <?php
/** final class ArcanistPasteWorkflow
* Upload a chunk of text to the Paste application, or download one. extends ArcanistArcWorkflow {
*/
final class ArcanistPasteWorkflow extends ArcanistWorkflow {
private $id;
private $language;
private $title;
private $json;
public function getWorkflowName() { public function getWorkflowName() {
return 'paste'; return 'paste';
} }
public function getCommandSynopses() { public function getWorkflowInformation() {
return phutil_console_format(<<<EOTEXT $help = pht(<<<EOTEXT
**paste** [--title __title__] [--lang __language__] [--json] Share and grab text using the Paste application. To create a paste,
**paste** __id__ [--json] use stdin to provide the text:
$ cat list_of_ducks.txt | arc paste
To retrieve a paste, specify the paste ID:
$ arc paste P123
EOTEXT EOTEXT
); );
return $this->newWorkflowInformation()
->addExample('**paste** [__options__] --')
->addExample('**paste** [__options__] -- __object__')
->setHelp($help);
} }
public function getCommandHelp() { public function getWorkflowArguments() {
return phutil_console_format(<<<EOTEXT
Supports: text
Share and grab text using the Paste application. To create a paste,
use stdin to provide the text:
$ cat list_of_ducks.txt | arc paste
To retrieve a paste, specify the paste ID:
$ arc paste P123
EOTEXT
);
}
public function getArguments() {
return array( return array(
'title' => array( $this->newWorkflowArgument('title')
'param' => 'title', ->setParameter('title')
'help' => pht('Title for the paste.'), ->setHelp(pht('Title for the paste.')),
), $this->newWorkflowArgument('lang')
'lang' => array( ->setParameter('language')
'param' => 'language', ->setHelp(pht('Language for the paste.')),
'help' => pht('Language for syntax highlighting.'), $this->newWorkflowArgument('json')
), ->setHelp(pht('Output in JSON format.')),
'json' => array( $this->newWorkflowArgument('argv')
'help' => pht('Output in JSON format.'), ->setWildcard(true),
),
'*' => 'argv',
); );
} }
public function requiresAuthentication() { public function runWorkflow() {
return true; $set_language = $this->getArgument('lang');
} $set_title = $this->getArgument('title');
protected function didParseArguments() {
$this->json = $this->getArgument('json');
$this->language = $this->getArgument('lang');
$this->title = $this->getArgument('title');
$argv = $this->getArgument('argv'); $argv = $this->getArgument('argv');
if (count($argv) > 1) { if (count($argv) > 1) {
throw new ArcanistUsageException( throw new PhutilArgumentUsageException(
pht('Specify only one paste to retrieve.')); pht(
} else if (count($argv) == 1) { 'Specify only one paste to retrieve.'));
$id = $argv[0]; }
if (!preg_match('/^P?\d+/', $id)) {
throw new ArcanistUsageException( $symbols = $this->getSymbolEngine();
if (count($argv) === 1) {
if ($set_language !== null) {
throw new PhutilArgumentUsageException(
pht( pht(
'Specify a paste ID, like %s.', 'Flag "--lang" is not supported when reading pastes.'));
'P123'));
} }
$this->id = (int)ltrim($id, 'P');
if ($this->language || $this->title) { if ($set_title !== null) {
throw new ArcanistUsageException( throw new PhutilArgumentUsageException(
pht( pht(
'Use options %s and %s only when creating pastes.', 'Flag "--title" is not supported when reading pastes.'));
'--lang',
'--title'));
} }
}
}
public function run() { $paste_symbol = $argv[0];
if ($this->id) {
return $this->getPaste();
} else {
return $this->createPaste();
}
}
private function getPaste() { $paste_ref = $symbols->loadPasteForSymbol($paste_symbol);
$conduit = $this->getConduit(); if (!$paste_ref) {
throw new PhutilArgumentUsageException(
$info = $conduit->callMethodSynchronous( pht(
'paste.query', 'Paste "%s" does not exist, or you do not have access '.
array( 'to see it.'));
'ids' => array($this->id),
));
$info = head($info);
if ($this->json) {
echo json_encode($info)."\n";
} else {
echo $info['content'];
if (!preg_match('/\\n$/', $info['content'])) {
// If there's no newline, add one, since it looks stupid otherwise. If
// you want byte-for-byte equivalence you can use `--json`.
echo "\n";
} }
echo $paste_ref->getContent();
return 0;
} }
return 0; $content = $this->readStdin();
}
private function createPaste() { $xactions = array();
$conduit = $this->getConduit();
if (!function_exists('posix_isatty') || posix_isatty(STDIN)) { if ($set_title === null) {
$this->writeStatusMessage(pht('Reading paste from stdin...')."\n"); $set_title = pht('Command-Line Input');
} }
$info = $conduit->callMethodSynchronous( $xactions[] = array(
'paste.create', 'type' => 'title',
array( 'value' => $set_title,
'content' => file_get_contents('php://stdin'), );
'title' => $this->title,
'language' => $this->language,
));
if ($this->getArgument('json')) { if ($set_language !== null) {
echo json_encode($info)."\n"; $xactions[] = array(
} else { 'type' => 'language',
echo $info['objectName'].': '.$info['uri']."\n"; 'value' => $set_language,
);
} }
$xactions[] = array(
'type' => 'text',
'value' => $content,
);
$method = 'paste.edit';
$parameters = array(
'transactions' => $xactions,
);
$conduit_engine = $this->getConduitEngine();
$conduit_call = $conduit_engine->newCall($method, $parameters);
$conduit_future = $conduit_engine->newFuture($conduit_call);
$result = $conduit_future->resolve();
$paste_phid = idxv($result, array('object', 'phid'));
$paste_ref = $symbols->loadPasteForSymbol($paste_phid);
$log = $this->getLogEngine();
$log->writeSuccess(
pht('DONE'),
pht('Created a new paste.'));
echo tsprintf(
'%s',
$paste_ref->newDisplayRef()
->setURI($paste_ref->getURI()));
return 0; return 0;
} }

View file

@ -52,7 +52,6 @@ abstract class ArcanistWorkflow extends Phobject {
private $repositoryAPI; private $repositoryAPI;
private $configurationManager; private $configurationManager;
private $arguments = array(); private $arguments = array();
private $passedArguments = array();
private $command; private $command;
private $stashed; private $stashed;
@ -777,10 +776,6 @@ abstract class ArcanistWorkflow extends Phobject {
return $this->arguments->getArg($key); return $this->arguments->getArg($key);
} }
final public function getPassedArguments() {
return $this->passedArguments;
}
final public function getCompleteArgumentSpecification() { final public function getCompleteArgumentSpecification() {
$spec = $this->getArguments(); $spec = $this->getArguments();
$arc_config = $this->getArcanistConfiguration(); $arc_config = $this->getArcanistConfiguration();
@ -791,8 +786,6 @@ abstract class ArcanistWorkflow extends Phobject {
} }
final public function parseArguments(array $args) { final public function parseArguments(array $args) {
$this->passedArguments = $args;
$spec = $this->getCompleteArgumentSpecification(); $spec = $this->getCompleteArgumentSpecification();
$dict = array(); $dict = array();
@ -2411,4 +2404,21 @@ abstract class ArcanistWorkflow extends Phobject {
return $this->getRuntime()->getViewer(); return $this->getRuntime()->getViewer();
} }
final protected function readStdin() {
$log = $this->getLogEngine();
$log->writeWaitingForInput();
// NOTE: We can't just "file_get_contents()" here because signals don't
// interrupt it. If the user types "^C", we want to interrupt the read.
$raw_handle = fopen('php://stdin', 'rb');
$stdin = new PhutilSocketChannel($raw_handle);
while ($stdin->update()) {
PhutilChannel::waitForAny(array($stdin));
}
return $stdin->read();
}
} }