mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-30 02:32:42 +01:00
Recognize self-URI links to Diffusion files and give them special rendering behavior
Summary: Depends on D20530. Ref T13291. When users paste links to files in Diffusion into remarkup contexts, identify them and specialize the rendering. When the URIs are embedded with `{...}`, parse them in more detail. This is a lead-up to a `{src ...}` rule which will use the same `View` but give users more options to customize presentation. Test Plan: {F6463580} Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13291 Differential Revision: https://secure.phabricator.com/D20538
This commit is contained in:
parent
7c1f6519e0
commit
56e7bde68d
11 changed files with 348 additions and 26 deletions
|
@ -999,6 +999,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionServeController' => 'applications/diffusion/controller/DiffusionServeController.php',
|
||||
'DiffusionSetPasswordSettingsPanel' => 'applications/diffusion/panel/DiffusionSetPasswordSettingsPanel.php',
|
||||
'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php',
|
||||
'DiffusionSourceHyperlinkEngineExtension' => 'applications/diffusion/engineextension/DiffusionSourceHyperlinkEngineExtension.php',
|
||||
'DiffusionSourceLinkView' => 'applications/diffusion/view/DiffusionSourceLinkView.php',
|
||||
'DiffusionSubversionCommandEngine' => 'applications/diffusion/protocol/DiffusionSubversionCommandEngine.php',
|
||||
'DiffusionSubversionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionSSHWorkflow.php',
|
||||
'DiffusionSubversionServeSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSubversionServeSSHWorkflow.php',
|
||||
|
@ -4340,6 +4342,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRemarkupDocumentEngine' => 'applications/files/document/PhabricatorRemarkupDocumentEngine.php',
|
||||
'PhabricatorRemarkupEditField' => 'applications/transactions/editfield/PhabricatorRemarkupEditField.php',
|
||||
'PhabricatorRemarkupFigletBlockInterpreter' => 'infrastructure/markup/interpreter/PhabricatorRemarkupFigletBlockInterpreter.php',
|
||||
'PhabricatorRemarkupHyperlinkEngineExtension' => 'applications/remarkup/engineextension/PhabricatorRemarkupHyperlinkEngineExtension.php',
|
||||
'PhabricatorRemarkupUIExample' => 'applications/uiexample/examples/PhabricatorRemarkupUIExample.php',
|
||||
'PhabricatorRepositoriesSetupCheck' => 'applications/config/check/PhabricatorRepositoriesSetupCheck.php',
|
||||
'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php',
|
||||
|
@ -6681,6 +6684,8 @@ phutil_register_library_map(array(
|
|||
'DiffusionServeController' => 'DiffusionController',
|
||||
'DiffusionSetPasswordSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'DiffusionSetupException' => 'Exception',
|
||||
'DiffusionSourceHyperlinkEngineExtension' => 'PhabricatorRemarkupHyperlinkEngineExtension',
|
||||
'DiffusionSourceLinkView' => 'AphrontView',
|
||||
'DiffusionSubversionCommandEngine' => 'DiffusionCommandEngine',
|
||||
'DiffusionSubversionSSHWorkflow' => 'DiffusionSSHWorkflow',
|
||||
'DiffusionSubversionServeSSHWorkflow' => 'DiffusionSubversionSSHWorkflow',
|
||||
|
@ -6786,7 +6791,7 @@ phutil_register_library_map(array(
|
|||
'DoorkeeperExternalObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'DoorkeeperFeedStoryPublisher' => 'Phobject',
|
||||
'DoorkeeperFeedWorker' => 'FeedPushWorker',
|
||||
'DoorkeeperHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension',
|
||||
'DoorkeeperHyperlinkEngineExtension' => 'PhabricatorRemarkupHyperlinkEngineExtension',
|
||||
'DoorkeeperImportEngine' => 'Phobject',
|
||||
'DoorkeeperJIRAFeedWorker' => 'DoorkeeperFeedWorker',
|
||||
'DoorkeeperMissingLinkException' => 'Exception',
|
||||
|
@ -10595,6 +10600,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorRemarkupDocumentEngine' => 'PhabricatorDocumentEngine',
|
||||
'PhabricatorRemarkupEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorRemarkupFigletBlockInterpreter' => 'PhutilRemarkupBlockInterpreter',
|
||||
'PhabricatorRemarkupHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension',
|
||||
'PhabricatorRemarkupUIExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorRepositoriesSetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorRepository' => array(
|
||||
|
@ -10883,7 +10889,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorSecuritySetupCheck' => 'PhabricatorSetupCheck',
|
||||
'PhabricatorSelectEditField' => 'PhabricatorEditField',
|
||||
'PhabricatorSelectSetting' => 'PhabricatorSetting',
|
||||
'PhabricatorSelfHyperlinkEngineExtension' => 'PhutilRemarkupHyperlinkEngineExtension',
|
||||
'PhabricatorSelfHyperlinkEngineExtension' => 'PhabricatorRemarkupHyperlinkEngineExtension',
|
||||
'PhabricatorSessionsSettingsPanel' => 'PhabricatorSettingsPanel',
|
||||
'PhabricatorSetConfigType' => 'PhabricatorTextConfigType',
|
||||
'PhabricatorSetting' => 'Phobject',
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionSourceHyperlinkEngineExtension
|
||||
extends PhabricatorRemarkupHyperlinkEngineExtension {
|
||||
|
||||
const LINKENGINEKEY = 'diffusion-src';
|
||||
|
||||
public function processHyperlinks(array $hyperlinks) {
|
||||
$engine = $this->getEngine();
|
||||
$viewer = $engine->getConfig('viewer');
|
||||
|
||||
if (!$viewer) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hyperlinks = $this->getSelfLinks($hyperlinks);
|
||||
|
||||
$links = array();
|
||||
foreach ($hyperlinks as $link) {
|
||||
$uri = $link->getURI();
|
||||
$uri = new PhutilURI($uri);
|
||||
|
||||
$path = $uri->getPath();
|
||||
|
||||
$pattern =
|
||||
'(^'.
|
||||
'/(?:diffusion|source)'.
|
||||
'/(?P<identifier>[^/]+)'.
|
||||
'/browse'.
|
||||
'/(?P<blob>.*)'.
|
||||
'\z)';
|
||||
$matches = null;
|
||||
if (!preg_match($pattern, $path, $matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$links[] = array(
|
||||
'ref' => $link,
|
||||
'identifier' => $matches['identifier'],
|
||||
'blob' => $matches['blob'],
|
||||
);
|
||||
}
|
||||
|
||||
if (!$links) {
|
||||
return;
|
||||
}
|
||||
|
||||
$identifiers = ipull($links, 'identifier');
|
||||
|
||||
$query = id(new PhabricatorRepositoryQuery())
|
||||
->setViewer($viewer)
|
||||
->withIdentifiers($identifiers);
|
||||
|
||||
$query->execute();
|
||||
|
||||
$repository_map = $query->getIdentifierMap();
|
||||
|
||||
foreach ($links as $link) {
|
||||
$identifier = $link['identifier'];
|
||||
|
||||
$repository = idx($repository_map, $identifier);
|
||||
if (!$repository) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$ref = $link['ref'];
|
||||
$uri = $ref->getURI();
|
||||
|
||||
|
||||
$tag = id(new DiffusionSourceLinkView())
|
||||
->setViewer($viewer)
|
||||
->setRepository($repository)
|
||||
->setURI($uri)
|
||||
->setBlob($link['blob']);
|
||||
|
||||
if (!$ref->isEmbed()) {
|
||||
$tag->setText($uri);
|
||||
}
|
||||
|
||||
$ref->setResult($tag);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
final class DiffusionGitRequest extends DiffusionRequest {
|
||||
|
||||
public function supportsBranches() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isStableCommit($symbol) {
|
||||
return preg_match('/^[a-f0-9]{40}\z/', $symbol);
|
||||
}
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
final class DiffusionMercurialRequest extends DiffusionRequest {
|
||||
|
||||
public function supportsBranches() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function isStableCommit($symbol) {
|
||||
return preg_match('/^[a-f0-9]{40}\z/', $symbol);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,10 @@ abstract class DiffusionRequest extends Phobject {
|
|||
private $branchObject = false;
|
||||
private $refAlternatives;
|
||||
|
||||
abstract public function supportsBranches();
|
||||
final public function supportsBranches() {
|
||||
return $this->getRepository()->supportsRefs();
|
||||
}
|
||||
|
||||
abstract protected function isStableCommit($symbol);
|
||||
|
||||
protected function didInitialize() {
|
||||
|
|
|
@ -2,10 +2,6 @@
|
|||
|
||||
final class DiffusionSvnRequest extends DiffusionRequest {
|
||||
|
||||
public function supportsBranches() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isStableCommit($symbol) {
|
||||
return preg_match('/^[1-9]\d*\z/', $symbol);
|
||||
}
|
||||
|
|
208
src/applications/diffusion/view/DiffusionSourceLinkView.php
Normal file
208
src/applications/diffusion/view/DiffusionSourceLinkView.php
Normal file
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
final class DiffusionSourceLinkView
|
||||
extends AphrontView {
|
||||
|
||||
private $repository;
|
||||
private $text;
|
||||
private $uri;
|
||||
private $blob;
|
||||
private $blobMap;
|
||||
private $refName;
|
||||
private $path;
|
||||
private $line;
|
||||
private $commit;
|
||||
|
||||
public function setRepository($repository) {
|
||||
$this->repository = $repository;
|
||||
$this->blobMap = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRepository() {
|
||||
return $this->repository;
|
||||
}
|
||||
|
||||
public function setText($text) {
|
||||
$this->text = $text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getText() {
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
public function setURI($uri) {
|
||||
$this->uri = $uri;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getURI() {
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
public function setBlob($blob) {
|
||||
$this->blob = $blob;
|
||||
$this->blobMap = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBlob() {
|
||||
return $this->blob;
|
||||
}
|
||||
|
||||
public function setRefName($ref_name) {
|
||||
$this->refName = $ref_name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRefName() {
|
||||
return $this->refName;
|
||||
}
|
||||
|
||||
public function setPath($path) {
|
||||
$this->path = $path;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPath() {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
public function setCommit($commit) {
|
||||
$this->commit = $commit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCommit() {
|
||||
return $this->commit;
|
||||
}
|
||||
|
||||
public function setLine($line) {
|
||||
$this->line = $line;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLine() {
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
public function getDisplayPath() {
|
||||
if ($this->path !== null) {
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
return $this->getBlobPath();
|
||||
}
|
||||
|
||||
public function getDisplayRefName() {
|
||||
if ($this->refName !== null) {
|
||||
return $this->refName;
|
||||
}
|
||||
|
||||
return $this->getBlobRefName();
|
||||
}
|
||||
|
||||
public function getDisplayCommit() {
|
||||
if ($this->commit !== null) {
|
||||
return $this->commit;
|
||||
}
|
||||
|
||||
return $this->getBlobCommit();
|
||||
}
|
||||
|
||||
public function getDisplayLine() {
|
||||
if ($this->line !== null) {
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
return $this->getBlobLine();
|
||||
}
|
||||
|
||||
private function getBlobPath() {
|
||||
return idx($this->getBlobMap(), 'path');
|
||||
}
|
||||
|
||||
private function getBlobRefName() {
|
||||
return idx($this->getBlobMap(), 'branch');
|
||||
}
|
||||
|
||||
private function getBlobLine() {
|
||||
return idx($this->getBlobMap(), 'line');
|
||||
}
|
||||
|
||||
private function getBlobCommit() {
|
||||
return idx($this->getBlobMap(), 'commit');
|
||||
}
|
||||
|
||||
private function getBlobMap() {
|
||||
if ($this->blobMap === null) {
|
||||
$repository = $this->getRepository();
|
||||
$blob = $this->blob;
|
||||
|
||||
if ($repository && ($blob !== null)) {
|
||||
$map = DiffusionRequest::parseRequestBlob(
|
||||
$blob,
|
||||
$repository->supportsRefs());
|
||||
} else {
|
||||
$map = array();
|
||||
}
|
||||
|
||||
$this->blobMap = $map;
|
||||
}
|
||||
|
||||
return $this->blobMap;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$repository = $this->getRepository();
|
||||
$uri = $this->getURI();
|
||||
|
||||
$color = 'blue';
|
||||
$icon = 'fa-file-text-o';
|
||||
|
||||
$text = $this->getText();
|
||||
if (!strlen($text)) {
|
||||
$path = $this->getDisplayPath();
|
||||
|
||||
$line = $this->getDisplayLine();
|
||||
if ($line !== null) {
|
||||
$path = pht('%s:%s', $path, $line);
|
||||
}
|
||||
|
||||
if ($repository) {
|
||||
$path = pht('%s %s', $repository->getMonogram(), $path);
|
||||
}
|
||||
|
||||
if ($repository && $repository->supportsRefs()) {
|
||||
$default_ref = $repository->getDefaultBranch();
|
||||
} else {
|
||||
$default_ref = null;
|
||||
}
|
||||
|
||||
$ref_name = $this->getDisplayRefName();
|
||||
if ($ref_name === $default_ref) {
|
||||
$ref_name = null;
|
||||
}
|
||||
|
||||
$commit = $this->getDisplayCommit();
|
||||
if ($ref_name !== null && $commit !== null) {
|
||||
$text = pht('%s (on %s at %s)', $path, $ref_name, $commit);
|
||||
} else if ($ref_name !== null) {
|
||||
$text = pht('%s (on %s)', $path, $ref_name);
|
||||
} else if ($commit !== null) {
|
||||
$text = pht('%s (at %s)', $path, $commit);
|
||||
} else {
|
||||
$text = $path;
|
||||
}
|
||||
}
|
||||
|
||||
return id(new PHUITagView())
|
||||
->setType(PHUITagView::TYPE_SHADE)
|
||||
->setColor($color)
|
||||
->setIcon($icon)
|
||||
->setHref($uri)
|
||||
->setName($text);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class DoorkeeperHyperlinkEngineExtension
|
||||
extends PhutilRemarkupHyperlinkEngineExtension {
|
||||
extends PhabricatorRemarkupHyperlinkEngineExtension {
|
||||
|
||||
const LINKENGINEKEY = 'doorkeeper';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorSelfHyperlinkEngineExtension
|
||||
extends PhutilRemarkupHyperlinkEngineExtension {
|
||||
extends PhabricatorRemarkupHyperlinkEngineExtension {
|
||||
|
||||
const LINKENGINEKEY = 'phabricator-self';
|
||||
|
||||
|
@ -15,15 +15,7 @@ final class PhabricatorSelfHyperlinkEngineExtension
|
|||
return;
|
||||
}
|
||||
|
||||
// Find links which point to resources on the Phabricator install itself.
|
||||
// We're going to try to enhance these.
|
||||
$self_links = array();
|
||||
foreach ($hyperlinks as $link) {
|
||||
$uri = $link->getURI();
|
||||
if (PhabricatorEnv::isSelfURI($uri)) {
|
||||
$self_links[] = $link;
|
||||
}
|
||||
}
|
||||
$self_links = $this->getSelfLinks($hyperlinks);
|
||||
|
||||
// For links in the form "/X123", we can reasonably guess that they are
|
||||
// fairly likely to be object names. Try to look them up.
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorRemarkupHyperlinkEngineExtension
|
||||
extends PhutilRemarkupHyperlinkEngineExtension {
|
||||
|
||||
final protected function getSelfLinks(array $hyperlinks) {
|
||||
assert_instances_of($hyperlinks, 'PhutilRemarkupHyperlinkRef');
|
||||
|
||||
$allowed_protocols = array(
|
||||
'http' => true,
|
||||
'https' => true,
|
||||
);
|
||||
|
||||
$results = array();
|
||||
foreach ($hyperlinks as $link) {
|
||||
$uri = $link->getURI();
|
||||
|
||||
if (!PhabricatorEnv::isSelfURI($uri)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$protocol = id(new PhutilURI($uri))->getProtocol();
|
||||
if (!isset($allowed_protocols[$protocol])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$results[] = $link;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
}
|
|
@ -2040,6 +2040,15 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function supportsRefs() {
|
||||
if ($this->isSVN()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getAlmanacServiceCacheKey() {
|
||||
$service_phid = $this->getAlmanacServicePHID();
|
||||
if (!$service_phid) {
|
||||
|
|
Loading…
Reference in a new issue