@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Framework for external symbol search

Summary:
Ref T7984. With this, an install can add an ExternalSymbolsSource to src/extensions, which will include whatever
source they have.

Test Plan: search for php and python builtins.

Reviewers: joshuaspence, epriestley, #blessed_reviewers

Reviewed By: epriestley, #blessed_reviewers

Subscribers: Korvin, epriestley

Maniphest Tasks: T7984

Differential Revision: https://secure.phabricator.com/D13036

authored by

Aviv Eyal and committed by
epriestley
8ea13f3c 445caf1d

+338 -46
+6
src/__phutil_library_map__.php
··· 507 507 'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php', 508 508 'DiffusionExistsQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionExistsQueryConduitAPIMethod.php', 509 509 'DiffusionExternalController' => 'applications/diffusion/controller/DiffusionExternalController.php', 510 + 'DiffusionExternalSymbolQuery' => 'applications/diffusion/symbol/DiffusionExternalSymbolQuery.php', 511 + 'DiffusionExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionExternalSymbolsSource.php', 510 512 'DiffusionFileContent' => 'applications/diffusion/data/DiffusionFileContent.php', 511 513 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionFileContentQuery.php', 512 514 'DiffusionFileContentQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionFileContentQueryConduitAPIMethod.php', ··· 565 567 'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/__tests__/DiffusionPathQueryTestCase.php', 566 568 'DiffusionPathTreeController' => 'applications/diffusion/controller/DiffusionPathTreeController.php', 567 569 'DiffusionPathValidateController' => 'applications/diffusion/controller/DiffusionPathValidateController.php', 570 + 'DiffusionPhpExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPhpExternalSymbolsSource.php', 568 571 'DiffusionPushCapability' => 'applications/diffusion/capability/DiffusionPushCapability.php', 569 572 'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php', 570 573 'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php', 571 574 'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php', 572 575 'DiffusionPushLogListView' => 'applications/diffusion/view/DiffusionPushLogListView.php', 576 + 'DiffusionPythonExternalSymbolsSource' => 'applications/diffusion/symbol/DiffusionPythonExternalSymbolsSource.php', 573 577 'DiffusionQuery' => 'applications/diffusion/query/DiffusionQuery.php', 574 578 'DiffusionQueryCommitsConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionQueryCommitsConduitAPIMethod.php', 575 579 'DiffusionQueryConduitAPIMethod' => 'applications/diffusion/conduit/DiffusionQueryConduitAPIMethod.php', ··· 3803 3807 'DiffusionPathQueryTestCase' => 'PhabricatorTestCase', 3804 3808 'DiffusionPathTreeController' => 'DiffusionController', 3805 3809 'DiffusionPathValidateController' => 'DiffusionController', 3810 + 'DiffusionPhpExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 3806 3811 'DiffusionPushCapability' => 'PhabricatorPolicyCapability', 3807 3812 'DiffusionPushEventViewController' => 'DiffusionPushLogController', 3808 3813 'DiffusionPushLogController' => 'DiffusionController', 3809 3814 'DiffusionPushLogListController' => 'DiffusionPushLogController', 3810 3815 'DiffusionPushLogListView' => 'AphrontView', 3816 + 'DiffusionPythonExternalSymbolsSource' => 'DiffusionExternalSymbolsSource', 3811 3817 'DiffusionQuery' => 'PhabricatorQuery', 3812 3818 'DiffusionQueryCommitsConduitAPIMethod' => 'DiffusionConduitAPIMethod', 3813 3819 'DiffusionQueryConduitAPIMethod' => 'DiffusionConduitAPIMethod',
+52 -46
src/applications/diffusion/controller/DiffusionSymbolController.php
··· 12 12 ->setViewer($user) 13 13 ->setName($this->name); 14 14 15 - if ($request->getStr('context') !== null) { 15 + if ($request->getStr('context')) { 16 16 $query->setContext($request->getStr('context')); 17 17 } 18 18 ··· 47 47 48 48 $symbols = $query->execute(); 49 49 50 - // For PHP builtins, jump to php.net documentation. 51 - if ($request->getBool('jump') && count($symbols) == 0) { 52 - if ($request->getStr('lang', 'php') == 'php') { 53 - if ($request->getStr('type', 'function') == 'function') { 54 - $functions = get_defined_functions(); 55 - if (in_array($this->name, $functions['internal'])) { 56 - return id(new AphrontRedirectResponse()) 57 - ->setIsExternal(true) 58 - ->setURI('http://www.php.net/function.'.$this->name); 59 - } 60 - } 61 - if ($request->getStr('type', 'class') == 'class') { 62 - if (class_exists($this->name, false) || 63 - interface_exists($this->name, false)) { 64 - if (id(new ReflectionClass($this->name))->isInternal()) { 65 - return id(new AphrontRedirectResponse()) 66 - ->setIsExternal(true) 67 - ->setURI('http://www.php.net/class.'.$this->name); 68 - } 69 - } 70 - } 71 - } 50 + 51 + 52 + $external_query = id(new DiffusionExternalSymbolQuery()) 53 + ->withNames(array($this->name)); 54 + 55 + if ($request->getStr('context')) { 56 + $external_query->withContexts(array($request->getStr('context'))); 57 + } 58 + 59 + if ($request->getStr('type')) { 60 + $external_query->withTypes(array($request->getStr('type'))); 61 + } 62 + 63 + if ($request->getStr('lang')) { 64 + $external_query->withLanguages(array($request->getStr('lang'))); 65 + } 66 + 67 + $external_sources = id(new PhutilSymbolLoader()) 68 + ->setAncestorClass('DiffusionExternalSymbolsSource') 69 + ->loadObjects(); 70 + $results = array($symbols); 71 + foreach ($external_sources as $source) { 72 + $results[] = $source->executeQuery($external_query); 73 + } 74 + $symbols = array_mergev($results); 75 + 76 + if ($request->getBool('jump') && count($symbols) == 1) { 77 + // If this is a clickthrough from Differential, just jump them 78 + // straight to the target if we got a single hit. 79 + $symbol = head($symbols); 80 + return id(new AphrontRedirectResponse()) 81 + ->setIsExternal($symbol->isExternal()) 82 + ->setURI($symbol->getURI()); 72 83 } 73 84 74 85 $rows = array(); 75 86 foreach ($symbols as $symbol) { 76 - $file = $symbol->getPath(); 77 - $line = $symbol->getLineNumber(); 87 + $href = $symbol->getURI(); 78 88 79 - $repo = $symbol->getRepository(); 80 - if ($repo) { 81 - $href = $symbol->getURI(); 89 + if ($symbol->isExternal()) { 90 + $source = $symbol->getSource(); 91 + $location = $symbol->getLocation(); 92 + } else { 93 + $repo = $symbol->getRepository(); 94 + $file = $symbol->getPath(); 95 + $line = $symbol->getLineNumber(); 82 96 83 - if ($request->getBool('jump') && count($symbols) == 1) { 84 - // If this is a clickthrough from Differential, just jump them 85 - // straight to the target if we got a single hit. 86 - return id(new AphrontRedirectResponse())->setURI($href); 87 - } 88 - 89 - $location = phutil_tag( 90 - 'a', 91 - array( 92 - 'href' => $href, 93 - ), 94 - $file.':'.$line); 95 - } else if ($file) { 97 + $source = $repo->getMonogram(); 96 98 $location = $file.':'.$line; 97 - } else { 98 - $location = '?'; 99 99 } 100 + $location = phutil_tag( 101 + 'a', 102 + array( 103 + 'href' => $href, 104 + ), 105 + $location); 100 106 101 107 $rows[] = array( 102 108 $symbol->getSymbolType(), 103 109 $symbol->getSymbolContext(), 104 110 $symbol->getSymbolName(), 105 111 $symbol->getSymbolLanguage(), 106 - $repo->getMonogram(), 112 + $source, 107 113 $location, 108 114 ); 109 115 } ··· 115 121 pht('Context'), 116 122 pht('Name'), 117 123 pht('Language'), 118 - pht('Repository'), 119 - pht('File'), 124 + pht('Source'), 125 + pht('Location'), 120 126 )); 121 127 $table->setColumnClasses( 122 128 array(
+46
src/applications/diffusion/symbol/DiffusionExternalSymbolQuery.php
··· 1 + <?php 2 + 3 + final class DiffusionExternalSymbolQuery { 4 + private $languages = array(); 5 + private $types = array(); 6 + private $names = array(); 7 + private $contexts = array(); 8 + 9 + public function withLanguages(array $languages) { 10 + $this->languages = $languages; 11 + return $this; 12 + } 13 + public function withTypes(array $types) { 14 + $this->types = $types; 15 + return $this; 16 + } 17 + public function withNames(array $names) { 18 + $this->names = $names; 19 + return $this; 20 + } 21 + public function withContexts(array $contexts) { 22 + $this->contexts = $contexts; 23 + return $this; 24 + } 25 + 26 + 27 + public function getLanguages() { 28 + return $this->languages; 29 + } 30 + public function getTypes() { 31 + return $this->types; 32 + } 33 + public function getNames() { 34 + return $this->names; 35 + } 36 + public function getContexts() { 37 + return $this->contexts; 38 + } 39 + 40 + public function matchesAnyLanguage(array $languages) { 41 + return (!$this->languages) || array_intersect($languages, $this->languages); 42 + } 43 + public function matchesAnyType(array $types) { 44 + return (!$this->types) || array_intersect($types, $this->types); 45 + } 46 + }
+15
src/applications/diffusion/symbol/DiffusionExternalSymbolsSource.php
··· 1 + <?php 2 + 3 + abstract class DiffusionExternalSymbolsSource { 4 + 5 + /** 6 + * @return list of PhabricatorRepositorySymbol 7 + */ 8 + abstract public function executeQuery(DiffusionExternalSymbolQuery $query); 9 + 10 + protected function buildExternalSymbol() { 11 + return id(new PhabricatorRepositorySymbol()) 12 + ->setIsExternal(true) 13 + ->makeEphemeral(); 14 + } 15 + }
+49
src/applications/diffusion/symbol/DiffusionPhpExternalSymbolsSource.php
··· 1 + <?php 2 + 3 + final class DiffusionPhpExternalSymbolsSource 4 + extends DiffusionExternalSymbolsSource { 5 + 6 + public function executeQuery(DiffusionExternalSymbolQuery $query) { 7 + $symbols = array(); 8 + 9 + if (!$query->matchesAnyLanguage(array('php'))) { 10 + return $symbols; 11 + } 12 + 13 + $names = $query->getNames(); 14 + 15 + if ($query->matchesAnyType(array('function'))) { 16 + $functions = get_defined_functions(); 17 + $functions = $functions['internal']; 18 + 19 + foreach ($names as $name) { 20 + if (in_array($name, $functions)) { 21 + $symbols[] = $this->buildExternalSymbol() 22 + ->setSymbolName($name) 23 + ->setSymbolType('function') 24 + ->setSource(pht('PHP')) 25 + ->setLocation(pht('Manual at php.net')) 26 + ->setSymbolLanguage('php') 27 + ->setExternalURI('http://www.php.net/function.'.$name); 28 + } 29 + } 30 + } 31 + if ($query->matchesAnyType(array('class'))) { 32 + foreach ($names as $name) { 33 + if (class_exists($name, false) || interface_exists($name, false)) { 34 + if (id(new ReflectionClass($name))->isInternal()) { 35 + $symbols[] = $this->buildExternalSymbol() 36 + ->setSymbolName($name) 37 + ->setSymbolType('class') 38 + ->setSource(pht('PHP')) 39 + ->setLocation(pht('Manual at php.net')) 40 + ->setSymbolLanguage('php') 41 + ->setExternalURI('http://www.php.net/class.'.$name); 42 + } 43 + } 44 + } 45 + } 46 + 47 + return $symbols; 48 + } 49 + }
+134
src/applications/diffusion/symbol/DiffusionPythonExternalSymbolsSource.php
··· 1 + <?php 2 + 3 + final class DiffusionPythonExternalSymbolsSource 4 + extends DiffusionExternalSymbolsSource { 5 + 6 + public function executeQuery(DiffusionExternalSymbolQuery $query) { 7 + $symbols = array(); 8 + if (!$query->matchesAnyLanguage(array('py', 'python'))) { 9 + return $symbols; 10 + } 11 + 12 + if (!$query->matchesAnyType(array('builtin', 'function'))) { 13 + return $symbols; 14 + } 15 + 16 + $names = $query->getNames(); 17 + 18 + foreach ($names as $name) { 19 + if (idx(self::$python2Builtins, $name)) { 20 + $symbols[] = $this->buildExternalSymbol() 21 + ->setSymbolName($name) 22 + ->setSymbolType('function') 23 + ->setSource(pht('Standard Library')) 24 + ->setLocation(pht('The Python 2 Standard Library')) 25 + ->setSymbolLanguage('py') 26 + ->setExternalURI( 27 + 'https://docs.python.org/2/library/functions.html#'.$name); 28 + } 29 + if (idx(self::$python3Builtins, $name)) { 30 + $symbols[] = $this->buildExternalSymbol() 31 + ->setSymbolName($name) 32 + ->setSymbolType('function') 33 + ->setSource(pht('Standard Library')) 34 + ->setLocation(pht('The Python 3 Standard Library')) 35 + ->setSymbolLanguage('py') 36 + ->setExternalURI( 37 + 'https://docs.python.org/3/library/functions.html#'.$name); 38 + } 39 + } 40 + return $symbols; 41 + } 42 + 43 + private static $python2Builtins = array( 44 + '__import__' => true, 45 + 'abs' => true, 46 + 'all' => true, 47 + 'any' => true, 48 + 'basestring' => true, 49 + 'bin' => true, 50 + 'bool' => true, 51 + 'bytearray' => true, 52 + 'callable' => true, 53 + 'chr' => true, 54 + 'classmethod' => true, 55 + 'cmp' => true, 56 + 'compile' => true, 57 + 'complex' => true, 58 + 'delattr' => true, 59 + 'dict' => true, 60 + 'dir' => true, 61 + 'divmod' => true, 62 + 'enumerate' => true, 63 + 'eval' => true, 64 + 'execfile' => true, 65 + 'file' => true, 66 + 'filter' => true, 67 + 'float' => true, 68 + 'format' => true, 69 + 'frozenset' => true, 70 + 'getattr' => true, 71 + 'globals' => true, 72 + 'hasattr' => true, 73 + 'hash' => true, 74 + 'help' => true, 75 + 'hex' => true, 76 + 'id' => true, 77 + 'input' => true, 78 + 'int' => true, 79 + 'isinstance' => true, 80 + 'issubclass' => true, 81 + 'iter' => true, 82 + 'len' => true, 83 + 'list' => true, 84 + 'locals' => true, 85 + 'long' => true, 86 + 'map' => true, 87 + 'max' => true, 88 + 'memoryview' => true, 89 + 'min' => true, 90 + 'next' => true, 91 + 'object' => true, 92 + 'oct' => true, 93 + 'open' => true, 94 + 'ord' => true, 95 + 'pow' => true, 96 + 'print' => true, 97 + 'property' => true, 98 + 'range' => true, 99 + 'raw_input' => true, 100 + 'reduce' => true, 101 + 'reload' => true, 102 + 'repr' => true, 103 + 'reversed' => true, 104 + 'round' => true, 105 + 'set' => true, 106 + 'setattr' => true, 107 + 'slice' => true, 108 + 'sorted' => true, 109 + 'staticmethod' => true, 110 + 'str' => true, 111 + 'sum' => true, 112 + 'super' => true, 113 + 'tuple' => true, 114 + 'type' => true, 115 + 'unichr' => true, 116 + 'unicode' => true, 117 + 'vars' => true, 118 + 'xrange' => true, 119 + 'zip' => true, 120 + ); 121 + 122 + // This list only contains functions that are new or changed between the 123 + // Python versions. 124 + private static $python3Builtins = array( 125 + 'ascii' => true, 126 + 'bytes' => true, 127 + 'filter' => true, 128 + 'map' => true, 129 + 'next' => true, 130 + 'range' => true, 131 + 'super' => true, 132 + 'zip' => true, 133 + ); 134 + }
+36
src/applications/repository/storage/PhabricatorRepositorySymbol.php
··· 15 15 protected $symbolLanguage; 16 16 protected $pathID; 17 17 protected $lineNumber; 18 + private $isExternal; 19 + private $source; 20 + private $location; 21 + private $externalURI; 18 22 19 23 private $path = self::ATTACHABLE; 20 24 private $repository = self::ATTACHABLE; ··· 40 44 } 41 45 42 46 public function getURI() { 47 + if ($this->isExternal) { 48 + return $this->externalURI; 49 + } 50 + 43 51 $request = DiffusionRequest::newFromDictionary( 44 52 array( 45 53 'user' => PhabricatorUser::getOmnipotentUser(), ··· 71 79 return $this; 72 80 } 73 81 82 + public function isExternal() { 83 + return $this->isExternal; 84 + } 85 + public function setIsExternal($is_external) { 86 + $this->isExternal = $is_external; 87 + return $this; 88 + } 89 + 90 + public function getSource() { 91 + return $this->source; 92 + } 93 + public function setSource($source) { 94 + $this->source = $source; 95 + return $this; 96 + } 97 + 98 + public function getLocation() { 99 + return $this->location; 100 + } 101 + public function setLocation($location) { 102 + $this->location = $location; 103 + return $this; 104 + } 105 + 106 + public function setExternalURI($external_uri) { 107 + $this->externalURI = $external_uri; 108 + return $this; 109 + } 74 110 }