1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-26 08:42:41 +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:
epriestley 2019-05-21 09:41:23 -07:00
parent 7c1f6519e0
commit 56e7bde68d
11 changed files with 348 additions and 26 deletions

View file

@ -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',

View file

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

View file

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

View file

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

View file

@ -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() {

View file

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

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

View file

@ -1,7 +1,7 @@
<?php
final class DoorkeeperHyperlinkEngineExtension
extends PhutilRemarkupHyperlinkEngineExtension {
extends PhabricatorRemarkupHyperlinkEngineExtension {
const LINKENGINEKEY = 'doorkeeper';

View file

@ -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.

View file

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

View file

@ -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) {