1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2024-12-22 21:40:54 +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',
'ArcanistFileDataRef' => 'upload/ArcanistFileDataRef.php',
'ArcanistFileRef' => 'ref/file/ArcanistFileRef.php',
'ArcanistFileSymbolHardpointQuery' => 'ref/file/ArcanistFileSymbolHardpointQuery.php',
'ArcanistFileSymbolRef' => 'ref/file/ArcanistFileSymbolRef.php',
'ArcanistFileSymbolRefInspector' => 'ref/file/ArcanistFileSymbolRefInspector.php',
'ArcanistFileUploader' => 'upload/ArcanistFileUploader.php',
'ArcanistFilenameLinter' => 'lint/linter/ArcanistFilenameLinter.php',
'ArcanistFilenameLinterTestCase' => 'lint/linter/__tests__/ArcanistFilenameLinterTestCase.php',
@ -361,6 +359,8 @@ phutil_register_library_map(array(
'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParenthesesSpacingXHPASTLinterRuleTestCase.php',
'ArcanistParseStrUseXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistParseStrUseXHPASTLinterRule.php',
'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistParseStrUseXHPASTLinterRuleTestCase.php',
'ArcanistPasteRef' => 'ref/paste/ArcanistPasteRef.php',
'ArcanistPasteSymbolRef' => 'ref/paste/ArcanistPasteSymbolRef.php',
'ArcanistPasteWorkflow' => 'workflow/ArcanistPasteWorkflow.php',
'ArcanistPatchWorkflow' => 'workflow/ArcanistPatchWorkflow.php',
'ArcanistPhpLinter' => 'lint/linter/ArcanistPhpLinter.php',
@ -401,9 +401,7 @@ phutil_register_library_map(array(
'ArcanistRevisionCommitMessageHardpointQuery' => 'ref/revision/ArcanistRevisionCommitMessageHardpointQuery.php',
'ArcanistRevisionRef' => 'ref/revision/ArcanistRevisionRef.php',
'ArcanistRevisionRefSource' => 'ref/ArcanistRevisionRefSource.php',
'ArcanistRevisionSymbolHardpointQuery' => 'ref/revision/ArcanistRevisionSymbolHardpointQuery.php',
'ArcanistRevisionSymbolRef' => 'ref/revision/ArcanistRevisionSymbolRef.php',
'ArcanistRevisionSymbolRefInspector' => 'ref/revision/ArcanistRevisionSymbolRefInspector.php',
'ArcanistRuboCopLinter' => 'lint/linter/ArcanistRuboCopLinter.php',
'ArcanistRuboCopLinterTestCase' => 'lint/linter/__tests__/ArcanistRuboCopLinterTestCase.php',
'ArcanistRubyLinter' => 'lint/linter/ArcanistRubyLinter.php',
@ -424,6 +422,9 @@ phutil_register_library_map(array(
'ArcanistSetting' => 'configuration/ArcanistSetting.php',
'ArcanistSettings' => 'configuration/ArcanistSettings.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',
'ArcanistSlownessXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSlownessXHPASTLinterRule.php',
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistSlownessXHPASTLinterRuleTestCase.php',
@ -439,6 +440,8 @@ phutil_register_library_map(array(
'ArcanistSymbolRef' => 'ref/symbol/ArcanistSymbolRef.php',
'ArcanistSyntaxErrorXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistSyntaxErrorXHPASTLinterRule.php',
'ArcanistSystemConfigurationSource' => 'config/source/ArcanistSystemConfigurationSource.php',
'ArcanistTaskRef' => 'ref/task/ArcanistTaskRef.php',
'ArcanistTaskSymbolRef' => 'ref/task/ArcanistTaskSymbolRef.php',
'ArcanistTasksWorkflow' => 'workflow/ArcanistTasksWorkflow.php',
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistTautologicalExpressionXHPASTLinterRule.php',
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistTautologicalExpressionXHPASTLinterRuleTestCase.php',
@ -1171,9 +1174,7 @@ phutil_register_library_map(array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistFileSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistFileSymbolRef' => 'ArcanistSymbolRef',
'ArcanistFileSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistFileSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistFileUploader' => 'Phobject',
'ArcanistFilenameLinter' => 'ArcanistLinter',
'ArcanistFilenameLinterTestCase' => 'ArcanistLinterTestCase',
@ -1343,7 +1344,12 @@ phutil_register_library_map(array(
'ArcanistParenthesesSpacingXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistParseStrUseXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistParseStrUseXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistPasteWorkflow' => 'ArcanistWorkflow',
'ArcanistPasteRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistPasteSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistPasteWorkflow' => 'ArcanistArcWorkflow',
'ArcanistPatchWorkflow' => 'ArcanistWorkflow',
'ArcanistPhpLinter' => 'ArcanistExternalLinter',
'ArcanistPhpLinterTestCase' => 'ArcanistExternalLinterTestCase',
@ -1386,9 +1392,7 @@ phutil_register_library_map(array(
'ArcanistDisplayRefInterface',
),
'ArcanistRevisionRefSource' => 'Phobject',
'ArcanistRevisionSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistRevisionSymbolRef' => 'ArcanistSymbolRef',
'ArcanistRevisionSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistRevisionSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistRuboCopLinter' => 'ArcanistExternalLinter',
'ArcanistRuboCopLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistRubyLinter' => 'ArcanistExternalLinter',
@ -1408,6 +1412,9 @@ phutil_register_library_map(array(
'ArcanistSetting' => 'Phobject',
'ArcanistSettings' => 'Phobject',
'ArcanistShellCompleteWorkflow' => 'ArcanistWorkflow',
'ArcanistSimpleSymbolHardpointQuery' => 'ArcanistRuntimeHardpointQuery',
'ArcanistSimpleSymbolRef' => 'ArcanistSymbolRef',
'ArcanistSimpleSymbolRefInspector' => 'ArcanistRefInspector',
'ArcanistSingleLintEngine' => 'ArcanistLintEngine',
'ArcanistSlownessXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSlownessXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@ -1423,6 +1430,11 @@ phutil_register_library_map(array(
'ArcanistSymbolRef' => 'ArcanistRef',
'ArcanistSyntaxErrorXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistSystemConfigurationSource' => 'ArcanistFilesystemConfigurationSource',
'ArcanistTaskRef' => array(
'ArcanistRef',
'ArcanistDisplayRefInterface',
),
'ArcanistTaskSymbolRef' => 'ArcanistSimpleSymbolRef',
'ArcanistTasksWorkflow' => 'ArcanistWorkflow',
'ArcanistTautologicalExpressionXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistTautologicalExpressionXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',

View file

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

View file

@ -6,11 +6,24 @@ abstract class ArcanistRefInspector
abstract public function getInspectFunctionName();
abstract public function newInspectRef(array $argv);
protected function newInspectors() {
return array($this);
}
final public static function getAllInspectors() {
return id(new PhutilClassMapQuery())
$base_inspectors = id(new PhutilClassMapQuery())
->setAncestorClass(__CLASS__)
->setUniqueMethod('getInspectFunctionName')
->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));
}
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 {
private $ref;
private $uri;
public function setRef(ArcanistRef $ref) {
$this->ref = $ref;
@ -16,6 +17,15 @@ final class ArcanistDisplayRef
return $this->ref;
}
public function setURI($uri) {
$this->uri = $uri;
return $this;
}
public function getURI() {
return $this->uri;
}
public function newTerminalString() {
$ref = $this->getRef();
@ -60,9 +70,20 @@ final class ArcanistDisplayRef
}
$ref = $this->getRef();
return tsprintf(
$output = array();
$output[] = tsprintf(
"<bg:cyan>** * **</bg> %s\n",
$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
final class ArcanistFileSymbolRef
extends ArcanistSymbolRef {
private $type;
const TYPE_ID = 'id';
const TYPE_PHID = 'phid';
extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() {
return pht('File Symbol "%s"', $this->getSymbol());
}
protected function newCacheKeyParts() {
return array(
sprintf('type(%s)', $this->type),
);
protected function getSimpleSymbolPrefixPattern() {
return '[Ff]?';
}
public function getSymbolType() {
return $this->type;
protected function getSimpleSymbolPHIDType() {
return 'FILE';
}
protected function resolveSymbol($symbol) {
$matches = null;
public function getSimpleSymbolConduitSearchMethodName() {
return 'file.search';
}
$is_id = preg_match('/^[Ff]?([1-9]\d*)\z/', $symbol, $matches);
if ($is_id) {
$this->type = self::TYPE_ID;
return (int)$matches[1];
}
public function getSimpleSymbolInspectFunctionName() {
return 'file';
}
$is_phid = preg_match('/^PHID-FILE-\S+\z/', $symbol, $matches);
if ($is_phid) {
$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));
public function newSimpleSymbolObjectRef() {
return new ArcanistFileRef();
}
}

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
final class ArcanistRevisionSymbolRef
extends ArcanistSymbolRef {
extends ArcanistSimpleSymbolRef {
public function getRefDisplayName() {
return pht('Revision Symbol "%s"', $this->getSymbol());
}
protected function resolveSymbol($symbol) {
$matches = null;
protected function getSimpleSymbolPrefixPattern() {
return '[Dd]?';
}
if (!preg_match('/^[Dd]?([1-9]\d*)\z/', $symbol, $matches)) {
throw new PhutilArgumentUsageException(
pht(
'The format of revision symbol "%s" is unrecognized. '.
'Expected a revision monogram like "D123", or a '.
'revision ID like "123".',
$symbol));
}
protected function getSimpleSymbolPHIDType() {
return 'DREV';
}
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
final class ArcanistFileSymbolHardpointQuery
final class ArcanistSimpleSymbolHardpointQuery
extends ArcanistRuntimeHardpointQuery {
public function getHardpoints() {
@ -10,7 +10,7 @@ final class ArcanistFileSymbolHardpointQuery
}
protected function canLoadRef(ArcanistRef $ref) {
return ($ref instanceof ArcanistFileSymbolRef);
return ($ref instanceof ArcanistSimpleSymbolRef);
}
public function loadHardpoint(array $refs, $hardpoint) {
@ -19,23 +19,31 @@ final class ArcanistFileSymbolHardpointQuery
foreach ($refs as $key => $ref) {
switch ($ref->getSymbolType()) {
case ArcanistFileSymbolRef::TYPE_ID:
case ArcanistSimpleSymbolRef::TYPE_ID:
$id_map[$key] = $ref->getSymbol();
break;
case ArcanistFileSymbolRef::TYPE_PHID:
case ArcanistSimpleSymbolRef::TYPE_PHID:
$phid_map[$key] = $ref->getSymbol();
break;
}
}
$template_ref = head($refs);
$conduit_method =
$template_ref->getSimpleSymbolConduitSearchMethodName();
$conduit_attachments =
$template_ref->getSimpleSymbolConduitSearchAttachments();
$futures = array();
if ($id_map) {
$id_future = $this->newConduitSearch(
'file.search',
$conduit_method,
array(
'ids' => array_values(array_fuse($id_map)),
));
),
$conduit_attachments);
$futures[] = $id_future;
} else {
@ -44,10 +52,11 @@ final class ArcanistFileSymbolHardpointQuery
if ($phid_map) {
$phid_future = $this->newConduitSearch(
'file.search',
$ref->getSimpleSymbolConduitSearchMethodName(),
array(
'phids' => array_values(array_fuse($phid_map)),
));
),
$conduit_attachments);
$futures[] = $phid_future;
} else {
@ -76,12 +85,16 @@ final class ArcanistFileSymbolHardpointQuery
}
}
$object_ref = $template_ref->newSimpleSymbolObjectRef();
foreach ($result_map as $key => $raw_result) {
if ($raw_result === null) {
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);

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);
}
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(
ArcanistSymbolRef $template,
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);
final public function newConduitSearch($method, $constraints) {
final public function newConduitSearch(
$method,
$constraints,
$attachments = array()) {
$conduit_engine = $this->getRuntime()
->getConduitEngine();
$conduit_future = id(new ConduitSearchFuture())
->setConduitEngine($conduit_engine)
->setMethod($method)
->setConstraints($constraints);
->setConstraints($constraints)
->setAttachments($attachments);
return $conduit_future;
}

View file

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

View file

@ -1,145 +1,137 @@
<?php
/**
* Upload a chunk of text to the Paste application, or download one.
*/
final class ArcanistPasteWorkflow extends ArcanistWorkflow {
private $id;
private $language;
private $title;
private $json;
final class ArcanistPasteWorkflow
extends ArcanistArcWorkflow {
public function getWorkflowName() {
return 'paste';
}
public function getCommandSynopses() {
return phutil_console_format(<<<EOTEXT
**paste** [--title __title__] [--lang __language__] [--json]
**paste** __id__ [--json]
public function getWorkflowInformation() {
$help = pht(<<<EOTEXT
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
);
return $this->newWorkflowInformation()
->addExample('**paste** [__options__] --')
->addExample('**paste** [__options__] -- __object__')
->setHelp($help);
}
public function getCommandHelp() {
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() {
public function getWorkflowArguments() {
return array(
'title' => array(
'param' => 'title',
'help' => pht('Title for the paste.'),
),
'lang' => array(
'param' => 'language',
'help' => pht('Language for syntax highlighting.'),
),
'json' => array(
'help' => pht('Output in JSON format.'),
),
'*' => 'argv',
$this->newWorkflowArgument('title')
->setParameter('title')
->setHelp(pht('Title for the paste.')),
$this->newWorkflowArgument('lang')
->setParameter('language')
->setHelp(pht('Language for the paste.')),
$this->newWorkflowArgument('json')
->setHelp(pht('Output in JSON format.')),
$this->newWorkflowArgument('argv')
->setWildcard(true),
);
}
public function requiresAuthentication() {
return true;
}
protected function didParseArguments() {
$this->json = $this->getArgument('json');
$this->language = $this->getArgument('lang');
$this->title = $this->getArgument('title');
public function runWorkflow() {
$set_language = $this->getArgument('lang');
$set_title = $this->getArgument('title');
$argv = $this->getArgument('argv');
if (count($argv) > 1) {
throw new ArcanistUsageException(
pht('Specify only one paste to retrieve.'));
} else if (count($argv) == 1) {
$id = $argv[0];
if (!preg_match('/^P?\d+/', $id)) {
throw new ArcanistUsageException(
throw new PhutilArgumentUsageException(
pht(
'Specify only one paste to retrieve.'));
}
$symbols = $this->getSymbolEngine();
if (count($argv) === 1) {
if ($set_language !== null) {
throw new PhutilArgumentUsageException(
pht(
'Specify a paste ID, like %s.',
'P123'));
'Flag "--lang" is not supported when reading pastes.'));
}
$this->id = (int)ltrim($id, 'P');
if ($this->language || $this->title) {
throw new ArcanistUsageException(
if ($set_title !== null) {
throw new PhutilArgumentUsageException(
pht(
'Use options %s and %s only when creating pastes.',
'--lang',
'--title'));
'Flag "--title" is not supported when reading pastes.'));
}
}
}
public function run() {
if ($this->id) {
return $this->getPaste();
} else {
return $this->createPaste();
}
}
$paste_symbol = $argv[0];
private function getPaste() {
$conduit = $this->getConduit();
$info = $conduit->callMethodSynchronous(
'paste.query',
array(
'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";
$paste_ref = $symbols->loadPasteForSymbol($paste_symbol);
if (!$paste_ref) {
throw new PhutilArgumentUsageException(
pht(
'Paste "%s" does not exist, or you do not have access '.
'to see it.'));
}
echo $paste_ref->getContent();
return 0;
}
return 0;
}
$content = $this->readStdin();
private function createPaste() {
$conduit = $this->getConduit();
$xactions = array();
if (!function_exists('posix_isatty') || posix_isatty(STDIN)) {
$this->writeStatusMessage(pht('Reading paste from stdin...')."\n");
if ($set_title === null) {
$set_title = pht('Command-Line Input');
}
$info = $conduit->callMethodSynchronous(
'paste.create',
array(
'content' => file_get_contents('php://stdin'),
'title' => $this->title,
'language' => $this->language,
));
$xactions[] = array(
'type' => 'title',
'value' => $set_title,
);
if ($this->getArgument('json')) {
echo json_encode($info)."\n";
} else {
echo $info['objectName'].': '.$info['uri']."\n";
if ($set_language !== null) {
$xactions[] = array(
'type' => 'language',
'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;
}

View file

@ -52,7 +52,6 @@ abstract class ArcanistWorkflow extends Phobject {
private $repositoryAPI;
private $configurationManager;
private $arguments = array();
private $passedArguments = array();
private $command;
private $stashed;
@ -777,10 +776,6 @@ abstract class ArcanistWorkflow extends Phobject {
return $this->arguments->getArg($key);
}
final public function getPassedArguments() {
return $this->passedArguments;
}
final public function getCompleteArgumentSpecification() {
$spec = $this->getArguments();
$arc_config = $this->getArcanistConfiguration();
@ -791,8 +786,6 @@ abstract class ArcanistWorkflow extends Phobject {
}
final public function parseArguments(array $args) {
$this->passedArguments = $args;
$spec = $this->getCompleteArgumentSpecification();
$dict = array();
@ -2411,4 +2404,21 @@ abstract class ArcanistWorkflow extends Phobject {
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();
}
}