mirror of
https://we.phorge.it/source/arcanist.git
synced 2025-01-24 21:48:20 +01:00
(stable) Promote 2020 Week 17
This commit is contained in:
commit
31c6b56b67
12 changed files with 362 additions and 160 deletions
|
@ -154,6 +154,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistDiffParserTestCase' => 'parser/__tests__/ArcanistDiffParserTestCase.php',
|
||||
'ArcanistDiffUtils' => 'difference/ArcanistDiffUtils.php',
|
||||
'ArcanistDiffUtilsTestCase' => 'difference/__tests__/ArcanistDiffUtilsTestCase.php',
|
||||
'ArcanistDiffVectorNode' => 'difference/ArcanistDiffVectorNode.php',
|
||||
'ArcanistDiffVectorTree' => 'difference/ArcanistDiffVectorTree.php',
|
||||
'ArcanistDiffWorkflow' => 'workflow/ArcanistDiffWorkflow.php',
|
||||
'ArcanistDifferentialCommitMessage' => 'differential/ArcanistDifferentialCommitMessage.php',
|
||||
'ArcanistDifferentialCommitMessageParserException' => 'differential/ArcanistDifferentialCommitMessageParserException.php',
|
||||
|
@ -691,7 +693,6 @@ phutil_register_library_map(array(
|
|||
'PhutilExecutionEnvironment' => 'utils/PhutilExecutionEnvironment.php',
|
||||
'PhutilFileLock' => 'filesystem/PhutilFileLock.php',
|
||||
'PhutilFileLockTestCase' => 'filesystem/__tests__/PhutilFileLockTestCase.php',
|
||||
'PhutilFileTree' => 'filesystem/PhutilFileTree.php',
|
||||
'PhutilFrenchLocale' => 'internationalization/locales/PhutilFrenchLocale.php',
|
||||
'PhutilGermanLocale' => 'internationalization/locales/PhutilGermanLocale.php',
|
||||
'PhutilGitBinaryAnalyzer' => 'filesystem/binary/PhutilGitBinaryAnalyzer.php',
|
||||
|
@ -1134,6 +1135,8 @@ phutil_register_library_map(array(
|
|||
'ArcanistDiffParserTestCase' => 'PhutilTestCase',
|
||||
'ArcanistDiffUtils' => 'Phobject',
|
||||
'ArcanistDiffUtilsTestCase' => 'PhutilTestCase',
|
||||
'ArcanistDiffVectorNode' => 'Phobject',
|
||||
'ArcanistDiffVectorTree' => 'Phobject',
|
||||
'ArcanistDiffWorkflow' => 'ArcanistWorkflow',
|
||||
'ArcanistDifferentialCommitMessage' => 'Phobject',
|
||||
'ArcanistDifferentialCommitMessageParserException' => 'Exception',
|
||||
|
@ -1702,7 +1705,6 @@ phutil_register_library_map(array(
|
|||
'PhutilExecutionEnvironment' => 'Phobject',
|
||||
'PhutilFileLock' => 'PhutilLock',
|
||||
'PhutilFileLockTestCase' => 'PhutilTestCase',
|
||||
'PhutilFileTree' => 'Phobject',
|
||||
'PhutilFrenchLocale' => 'PhutilLocale',
|
||||
'PhutilGermanLocale' => 'PhutilLocale',
|
||||
'PhutilGitBinaryAnalyzer' => 'PhutilBinaryAnalyzer',
|
||||
|
|
|
@ -234,21 +234,8 @@ EOTEXT
|
|||
|
||||
$ref_uri = head($ref_uris);
|
||||
|
||||
// TODO: "ArcanistRevisionRef", at least, may return a relative URI.
|
||||
// If we get a relative URI, guess the correct absolute URI based on
|
||||
// the Conduit URI. This might not be correct for Conduit over SSH.
|
||||
|
||||
$raw_uri = $ref_uri->getURI();
|
||||
|
||||
$raw_uri = new PhutilURI($raw_uri);
|
||||
if (!strlen($raw_uri->getDomain())) {
|
||||
$base_uri = $this->getConduitEngine()
|
||||
->getConduitURI();
|
||||
|
||||
$raw_uri = id(new PhutilURI($base_uri))
|
||||
->setPath($raw_uri->getPath());
|
||||
}
|
||||
$raw_uri = phutil_string_cast($raw_uri);
|
||||
$raw_uri = $this->getAbsoluteURI($raw_uri);
|
||||
|
||||
$uris[] = $raw_uri;
|
||||
}
|
||||
|
|
113
src/difference/ArcanistDiffVectorNode.php
Normal file
113
src/difference/ArcanistDiffVectorNode.php
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistDiffVectorNode
|
||||
extends Phobject {
|
||||
|
||||
private $vector;
|
||||
private $children = array();
|
||||
private $parentNode;
|
||||
private $displayNode;
|
||||
private $displayVector;
|
||||
private $displayDepth;
|
||||
private $valueNode;
|
||||
private $attributes = array();
|
||||
|
||||
public function setVector(array $vector) {
|
||||
$this->vector = $vector;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVector() {
|
||||
return $this->vector;
|
||||
}
|
||||
|
||||
public function getChildren() {
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
public function setParentNode(ArcanistDiffVectorNode $parent) {
|
||||
$this->parentNode = $parent;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getParentNode() {
|
||||
return $this->parentNode;
|
||||
}
|
||||
|
||||
public function addChild(array $vector, $length, $idx) {
|
||||
$is_node = ($idx === ($length - 1));
|
||||
$element = $vector[$idx];
|
||||
|
||||
if (!isset($this->children[$element])) {
|
||||
$this->children[$element] = id(new self())
|
||||
->setParentNode($this)
|
||||
->setVector(array_slice($vector, 0, $idx + 1));
|
||||
}
|
||||
|
||||
$child = $this->children[$element];
|
||||
|
||||
if ($is_node) {
|
||||
$child->setValueNode($child);
|
||||
return;
|
||||
}
|
||||
|
||||
$child->addChild($vector, $length, $idx + 1);
|
||||
}
|
||||
|
||||
public function getDisplayVector() {
|
||||
return $this->displayVector;
|
||||
}
|
||||
|
||||
public function appendDisplayElement($element) {
|
||||
if ($this->displayVector === null) {
|
||||
$this->displayVector = array();
|
||||
}
|
||||
|
||||
$this->displayVector[] = $element;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDisplayNode(ArcanistDiffVectorNode $display_node) {
|
||||
$this->displayNode = $display_node;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDisplayNode() {
|
||||
return $this->displayNode;
|
||||
}
|
||||
|
||||
public function setDisplayDepth($display_depth) {
|
||||
$this->displayDepth = $display_depth;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDisplayDepth() {
|
||||
return $this->displayDepth;
|
||||
}
|
||||
|
||||
public function setValueNode($value_node) {
|
||||
$this->valueNode = $value_node;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getValueNode() {
|
||||
return $this->valueNode;
|
||||
}
|
||||
|
||||
public function setAncestralAttribute($key, $value) {
|
||||
$this->attributes[$key] = $value;
|
||||
|
||||
$parent = $this->getParentNode();
|
||||
if ($parent) {
|
||||
$parent->setAncestralAttribute($key, $value);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAttribute($key, $default = null) {
|
||||
return idx($this->attributes, $key, $default);
|
||||
}
|
||||
|
||||
}
|
95
src/difference/ArcanistDiffVectorTree.php
Normal file
95
src/difference/ArcanistDiffVectorTree.php
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?php
|
||||
|
||||
final class ArcanistDiffVectorTree
|
||||
extends Phobject {
|
||||
|
||||
private $vectors;
|
||||
|
||||
public function addVector(array $vector) {
|
||||
$this->vectors[] = $vector;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function newDisplayList() {
|
||||
$root = new ArcanistDiffVectorNode();
|
||||
|
||||
foreach ($this->vectors as $vector) {
|
||||
$root->addChild($vector, count($vector), 0);
|
||||
}
|
||||
|
||||
foreach ($root->getChildren() as $child) {
|
||||
$this->compressTree($child);
|
||||
}
|
||||
|
||||
$root->setDisplayDepth(-1);
|
||||
foreach ($root->getChildren() as $child) {
|
||||
$this->updateDisplayDepth($child);
|
||||
}
|
||||
|
||||
return $this->getDisplayList($root);
|
||||
}
|
||||
|
||||
private function compressTree(ArcanistDiffVectorNode $node) {
|
||||
$display_node = $node;
|
||||
|
||||
$children = $node->getChildren();
|
||||
if ($children) {
|
||||
$parent = $node->getParentNode();
|
||||
if ($parent) {
|
||||
$siblings = $parent->getChildren();
|
||||
if (count($siblings) === 1) {
|
||||
if (!$parent->getValueNode()) {
|
||||
$parent_display = $parent->getDisplayNode();
|
||||
if ($parent_display) {
|
||||
$display_node = $parent_display;
|
||||
if ($node->getValueNode()) {
|
||||
$parent->setValueNode($node->getValueNode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$node->setDisplayNode($display_node);
|
||||
|
||||
$display_element = last($node->getVector());
|
||||
$display_node->appendDisplayElement($display_element);
|
||||
|
||||
foreach ($children as $child) {
|
||||
$this->compressTree($child);
|
||||
}
|
||||
}
|
||||
|
||||
private function updateDisplayDepth(ArcanistDiffVectorNode $node) {
|
||||
$parent_depth = $node->getParentNode()->getDisplayDepth();
|
||||
|
||||
if ($node->getDisplayVector() === null) {
|
||||
$display_depth = $parent_depth;
|
||||
} else {
|
||||
$display_depth = $parent_depth + 1;
|
||||
}
|
||||
|
||||
$node->setDisplayDepth($display_depth);
|
||||
|
||||
foreach ($node->getChildren() as $child) {
|
||||
$this->updateDisplayDepth($child);
|
||||
}
|
||||
}
|
||||
|
||||
private function getDisplayList(ArcanistDiffVectorNode $node) {
|
||||
$result = array();
|
||||
|
||||
foreach ($node->getChildren() as $child) {
|
||||
if ($child->getDisplayVector() !== null) {
|
||||
$result[] = $child;
|
||||
}
|
||||
foreach ($this->getDisplayList($child) as $item) {
|
||||
$result[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Data structure for representing filesystem directory trees.
|
||||
*/
|
||||
final class PhutilFileTree extends Phobject {
|
||||
|
||||
private $name;
|
||||
private $fullPath;
|
||||
private $data;
|
||||
private $depth = 0;
|
||||
private $parentNode;
|
||||
private $children = array();
|
||||
|
||||
public function addPath($path, $data) {
|
||||
$parts = $this->splitPath($path);
|
||||
$parts = array_reverse($parts);
|
||||
$this->insertPath($parts, $data);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function destroy() {
|
||||
$this->parentNode = null;
|
||||
foreach ($this->children as $child) {
|
||||
$child->destroy();
|
||||
}
|
||||
$this->children = array();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next node, iterating in depth-first order.
|
||||
*/
|
||||
public function getNextNode() {
|
||||
if ($this->children) {
|
||||
return head($this->children);
|
||||
}
|
||||
$cursor = $this;
|
||||
while ($cursor) {
|
||||
if ($cursor->getNextSibling()) {
|
||||
return $cursor->getNextSibling();
|
||||
}
|
||||
$cursor = $cursor->parentNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getFullPath() {
|
||||
return $this->fullPath;
|
||||
}
|
||||
|
||||
public function getDepth() {
|
||||
return $this->depth;
|
||||
}
|
||||
|
||||
public function getData() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
protected function insertPath(array $parts, $data) {
|
||||
$part = array_pop($parts);
|
||||
if ($part === null) {
|
||||
if ($this->data) {
|
||||
$full_path = $this->getFullPath();
|
||||
throw new Exception(
|
||||
pht("Duplicate insertion for path '%s'.", $full_path));
|
||||
}
|
||||
$this->data = $data;
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($this->children[$part])) {
|
||||
$node = new PhutilFileTree();
|
||||
$node->parentNode = $this;
|
||||
$node->depth = $this->depth + 1;
|
||||
$node->name = $part;
|
||||
$node->fullPath = $this->parentNode ? ($this->fullPath.'/'.$part) : $part;
|
||||
$this->children[$part] = $node;
|
||||
}
|
||||
|
||||
$this->children[$part]->insertPath($parts, $data);
|
||||
}
|
||||
|
||||
protected function splitPath($path) {
|
||||
$path = trim($path, '/');
|
||||
$parts = preg_split('@/+@', $path);
|
||||
return $parts;
|
||||
}
|
||||
|
||||
protected function getNextSibling() {
|
||||
if (!$this->parentNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$found = false;
|
||||
foreach ($this->parentNode->children as $node) {
|
||||
if ($found) {
|
||||
return $node;
|
||||
}
|
||||
if ($this->name === $node->name) {
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -41,15 +41,15 @@ abstract class Future extends Phobject {
|
|||
'timeout.'));
|
||||
}
|
||||
|
||||
if ($this->hasException()) {
|
||||
throw $this->getException();
|
||||
}
|
||||
|
||||
if (!$this->hasResult()) {
|
||||
if (!$this->hasResult() && !$this->hasException()) {
|
||||
$graph = new FutureIterator(array($this));
|
||||
$graph->resolveAll();
|
||||
}
|
||||
|
||||
if ($this->hasException()) {
|
||||
throw $this->getException();
|
||||
}
|
||||
|
||||
return $this->getResult();
|
||||
}
|
||||
|
||||
|
|
|
@ -713,7 +713,17 @@ final class ExecFuture extends PhutilExecutableFuture {
|
|||
while (isset($this->stdin) && $this->stdin->getByteLength()) {
|
||||
$write_segment = $this->stdin->getAnyPrefix();
|
||||
|
||||
try {
|
||||
$bytes = fwrite($stdin, $write_segment);
|
||||
} catch (RuntimeException $ex) {
|
||||
// If the subprocess has exited, we may get a broken pipe error here
|
||||
// in recent versions of PHP. There does not seem to be any way to
|
||||
// get the actual error code other than reading the exception string.
|
||||
|
||||
// For now, treat this as if writes are blocked.
|
||||
break;
|
||||
}
|
||||
|
||||
if ($bytes === false) {
|
||||
throw new Exception(pht('Unable to write to stdin!'));
|
||||
} else if ($bytes) {
|
||||
|
|
|
@ -37,6 +37,16 @@ final class ArcanistFileRef
|
|||
return idxv($this->parameters, array('fields', 'size'));
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
$uri = idxv($this->parameters, array('fields', 'uri'));
|
||||
|
||||
if ($uri === null) {
|
||||
$uri = '/'.$this->getMonogram();
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function getMonogram() {
|
||||
return 'F'.$this->getID();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,13 @@ final class ArcanistPasteRef
|
|||
}
|
||||
|
||||
public function getURI() {
|
||||
return idxv($this->parameters, array('fields', 'uri'));
|
||||
$uri = idxv($this->parameters, array('fields', 'uri'));
|
||||
|
||||
if ($uri === null) {
|
||||
$uri = '/'.$this->getMonogram();
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function getContent() {
|
||||
|
|
|
@ -9,10 +9,11 @@ final class ArcanistPasteWorkflow
|
|||
|
||||
public function getWorkflowInformation() {
|
||||
$help = pht(<<<EOTEXT
|
||||
Share and grab text using the Paste application. To create a paste,
|
||||
use stdin to provide the text:
|
||||
Share and grab text using the Paste application. To create a paste, use the
|
||||
"--input" flag or provide the text on stdin:
|
||||
|
||||
$ cat list_of_ducks.txt | arc paste
|
||||
$ arc paste --input list_of_ducks.txt
|
||||
|
||||
To retrieve a paste, specify the paste ID:
|
||||
|
||||
|
@ -34,8 +35,12 @@ EOTEXT
|
|||
$this->newWorkflowArgument('lang')
|
||||
->setParameter('language')
|
||||
->setHelp(pht('Language for the paste.')),
|
||||
$this->newWorkflowArgument('json')
|
||||
->setHelp(pht('Output in JSON format.')),
|
||||
$this->newWorkflowArgument('input')
|
||||
->setParameter('path')
|
||||
->setIsPathArgument(true)
|
||||
->setHelp(pht('Create a paste using the content in a file.')),
|
||||
$this->newWorkflowArgument('browse')
|
||||
->setHelp(pht('After creating a paste, open it in a web browser.')),
|
||||
$this->newWorkflowArgument('argv')
|
||||
->setWildcard(true),
|
||||
);
|
||||
|
@ -44,6 +49,8 @@ EOTEXT
|
|||
public function runWorkflow() {
|
||||
$set_language = $this->getArgument('lang');
|
||||
$set_title = $this->getArgument('title');
|
||||
$is_browse = $this->getArgument('browse');
|
||||
$input_path = $this->getArgument('input');
|
||||
|
||||
$argv = $this->getArgument('argv');
|
||||
if (count($argv) > 1) {
|
||||
|
@ -52,6 +59,8 @@ EOTEXT
|
|||
'Specify only one paste to retrieve.'));
|
||||
}
|
||||
|
||||
$is_read = (count($argv) === 1);
|
||||
|
||||
$symbols = $this->getSymbolEngine();
|
||||
|
||||
if (count($argv) === 1) {
|
||||
|
@ -67,6 +76,19 @@ EOTEXT
|
|||
'Flag "--title" is not supported when reading pastes.'));
|
||||
}
|
||||
|
||||
if ($is_browse) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Flag "--browse" is not supported when reading pastes. Use '.
|
||||
'"arc browse" to browse known objects.'));
|
||||
}
|
||||
|
||||
if ($input_path !== null) {
|
||||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Flag "--input" is not supported when reading pastes.'));
|
||||
}
|
||||
|
||||
$paste_symbol = $argv[0];
|
||||
|
||||
$paste_ref = $symbols->loadPasteForSymbol($paste_symbol);
|
||||
|
@ -74,7 +96,8 @@ EOTEXT
|
|||
throw new PhutilArgumentUsageException(
|
||||
pht(
|
||||
'Paste "%s" does not exist, or you do not have access '.
|
||||
'to see it.'));
|
||||
'to see it.',
|
||||
$paste_symbol));
|
||||
}
|
||||
|
||||
echo $paste_ref->getContent();
|
||||
|
@ -82,7 +105,11 @@ EOTEXT
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ($input_path === null || $input_path === '-') {
|
||||
$content = $this->readStdin();
|
||||
} else {
|
||||
$content = Filesystem::readFile($input_path);
|
||||
}
|
||||
|
||||
$xactions = array();
|
||||
|
||||
|
@ -121,6 +148,9 @@ EOTEXT
|
|||
$paste_phid = idxv($result, array('object', 'phid'));
|
||||
$paste_ref = $symbols->loadPasteForSymbol($paste_phid);
|
||||
|
||||
$uri = $paste_ref->getURI();
|
||||
$uri = $this->getAbsoluteURI($uri);
|
||||
|
||||
$log = $this->getLogEngine();
|
||||
|
||||
$log->writeSuccess(
|
||||
|
@ -130,7 +160,11 @@ EOTEXT
|
|||
echo tsprintf(
|
||||
'%s',
|
||||
$paste_ref->newDisplayRef()
|
||||
->setURI($paste_ref->getURI()));
|
||||
->setURI($uri));
|
||||
|
||||
if ($is_browse) {
|
||||
$this->openURIsInBrowser(array($uri));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,10 @@ EOTEXT
|
|||
return array(
|
||||
$this->newWorkflowArgument('json')
|
||||
->setHelp(pht('Output upload information in JSON format.')),
|
||||
$this->newWorkflowArgument('browse')
|
||||
->setHelp(
|
||||
pht(
|
||||
'After the upload completes, open the files in a web browser.')),
|
||||
$this->newWorkflowArgument('temporary')
|
||||
->setHelp(
|
||||
pht(
|
||||
|
@ -42,6 +46,7 @@ EOTEXT
|
|||
|
||||
$is_temporary = $this->getArgument('temporary');
|
||||
$is_json = $this->getArgument('json');
|
||||
$is_browse = $this->getArgument('browse');
|
||||
$paths = $this->getArgument('paths');
|
||||
|
||||
$conduit = $this->getConduitEngine();
|
||||
|
@ -65,35 +70,68 @@ EOTEXT
|
|||
|
||||
$files = $uploader->uploadFiles();
|
||||
|
||||
$results = array();
|
||||
$phids = array();
|
||||
foreach ($files as $file) {
|
||||
// TODO: This could be handled more gracefully; just preserving behavior
|
||||
// until we introduce `file.query` and modernize this.
|
||||
// TODO: This could be handled more gracefully.
|
||||
if ($file->getErrors()) {
|
||||
throw new Exception(implode("\n", $file->getErrors()));
|
||||
}
|
||||
$phid = $file->getPHID();
|
||||
$name = $file->getName();
|
||||
|
||||
$info = $conduit->resolveCall(
|
||||
'file.info',
|
||||
array(
|
||||
'phid' => $phid,
|
||||
));
|
||||
|
||||
$results[$path] = $info;
|
||||
|
||||
if (!$is_json) {
|
||||
$id = $info['id'];
|
||||
echo " F{$id} {$name}: ".$info['uri']."\n\n";
|
||||
$phids[] = $file->getPHID();
|
||||
}
|
||||
|
||||
$symbols = $this->getSymbolEngine();
|
||||
$symbol_refs = $symbols->loadFilesForSymbols($phids);
|
||||
|
||||
$refs = array();
|
||||
foreach ($symbol_refs as $symbol_ref) {
|
||||
$ref = $symbol_ref->getObject();
|
||||
if ($ref === null) {
|
||||
throw new Exception(
|
||||
pht(
|
||||
'Failed to resolve symbol ref "%s".',
|
||||
$symbol_ref->getSymbol()));
|
||||
}
|
||||
$refs[] = $ref;
|
||||
}
|
||||
|
||||
if ($is_json) {
|
||||
$output = id(new PhutilJSON())->encodeFormatted($results);
|
||||
echo $output;
|
||||
$json = array();
|
||||
|
||||
foreach ($refs as $key => $ref) {
|
||||
$uri = $ref->getURI();
|
||||
$uri = $this->getAbsoluteURI($uri);
|
||||
|
||||
$map = array(
|
||||
'argument' => $paths[$key],
|
||||
'id' => $ref->getID(),
|
||||
'phid' => $ref->getPHID(),
|
||||
'name' => $ref->getName(),
|
||||
'uri' => $uri,
|
||||
);
|
||||
|
||||
$json[] = $map;
|
||||
}
|
||||
|
||||
echo id(new PhutilJSON())->encodeAsList($json);
|
||||
} else {
|
||||
$this->writeStatus(pht('Done.'));
|
||||
foreach ($refs as $ref) {
|
||||
$uri = $ref->getURI();
|
||||
$uri = $this->getAbsoluteURI($uri);
|
||||
echo tsprintf(
|
||||
'%s',
|
||||
$ref->newDisplayRef()
|
||||
->setURI($uri));
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_browse) {
|
||||
$uris = array();
|
||||
foreach ($refs as $ref) {
|
||||
$uri = $ref->getURI();
|
||||
$uri = $this->getAbsoluteURI($uri);
|
||||
$uris[] = $uri;
|
||||
}
|
||||
$this->openURIsInBrowser($uris);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -2421,4 +2421,23 @@ abstract class ArcanistWorkflow extends Phobject {
|
|||
return $stdin->read();
|
||||
}
|
||||
|
||||
protected function getAbsoluteURI($raw_uri) {
|
||||
// TODO: "ArcanistRevisionRef", at least, may return a relative URI.
|
||||
// If we get a relative URI, guess the correct absolute URI based on
|
||||
// the Conduit URI. This might not be correct for Conduit over SSH.
|
||||
|
||||
$raw_uri = new PhutilURI($raw_uri);
|
||||
if (!strlen($raw_uri->getDomain())) {
|
||||
$base_uri = $this->getConduitEngine()
|
||||
->getConduitURI();
|
||||
|
||||
$raw_uri = id(new PhutilURI($base_uri))
|
||||
->setPath($raw_uri->getPath());
|
||||
}
|
||||
|
||||
$raw_uri = phutil_string_cast($raw_uri);
|
||||
|
||||
return $raw_uri;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue