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

Collapse repository URI normalization code into Arcanist

Summary: Ref T13546. Companion change to D21372. Move URI normalization code to Arcanist to we can more-often resolve remote URIs correctly.

Test Plan: Grepped for affected symbols.

Maniphest Tasks: T13546

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

+39 -260
-4
src/__phutil_library_map__.php
··· 4653 4653 'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php', 4654 4654 'PhabricatorRepositoryURI' => 'applications/repository/storage/PhabricatorRepositoryURI.php', 4655 4655 'PhabricatorRepositoryURIIndex' => 'applications/repository/storage/PhabricatorRepositoryURIIndex.php', 4656 - 'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php', 4657 - 'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php', 4658 4656 'PhabricatorRepositoryURIPHIDType' => 'applications/repository/phid/PhabricatorRepositoryURIPHIDType.php', 4659 4657 'PhabricatorRepositoryURIQuery' => 'applications/repository/query/PhabricatorRepositoryURIQuery.php', 4660 4658 'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php', ··· 11407 11405 'PhabricatorConduitResultInterface', 11408 11406 ), 11409 11407 'PhabricatorRepositoryURIIndex' => 'PhabricatorRepositoryDAO', 11410 - 'PhabricatorRepositoryURINormalizer' => 'Phobject', 11411 - 'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase', 11412 11408 'PhabricatorRepositoryURIPHIDType' => 'PhabricatorPHIDType', 11413 11409 'PhabricatorRepositoryURIQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 11414 11410 'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase',
-165
src/applications/repository/data/PhabricatorRepositoryURINormalizer.php
··· 1 - <?php 2 - 3 - /** 4 - * Normalize repository URIs. For example, these URIs are generally equivalent 5 - * and all point at the same repository: 6 - * 7 - * ssh://user@host/repo 8 - * ssh://user@host/repo/ 9 - * ssh://user@host:22/repo 10 - * user@host:/repo 11 - * ssh://user@host/repo.git 12 - * 13 - * This class can be used to normalize URIs like this, in order to detect 14 - * alternate spellings of the same repository URI. In particular, the 15 - * @{method:getNormalizedPath} method will return: 16 - * 17 - * repo 18 - * 19 - * ...for all of these URIs. Generally, usage looks like this: 20 - * 21 - * $norm_a = new PhabricatorRepositoryURINormalizer($type, $uri_a); 22 - * $norm_b = new PhabricatorRepositoryURINormalizer($type, $uri_b); 23 - * 24 - * if ($norm_a->getNormalizedPath() == $norm_b->getNormalizedPath()) { 25 - * // URIs appear to point at the same repository. 26 - * } else { 27 - * // URIs are very unlikely to be the same repository. 28 - * } 29 - * 30 - * Because a repository can be hosted at arbitrarily many arbitrary URIs, there 31 - * is no way to completely prevent false negatives by only examining URIs 32 - * (that is, repositories with totally different URIs could really be the same). 33 - * However, normalization is relatively aggressive and false negatives should 34 - * be rare: if normalization says two URIs are different repositories, they 35 - * probably are. 36 - * 37 - * @task normal Normalizing URIs 38 - */ 39 - final class PhabricatorRepositoryURINormalizer extends Phobject { 40 - 41 - const TYPE_GIT = 'git'; 42 - const TYPE_SVN = 'svn'; 43 - const TYPE_MERCURIAL = 'hg'; 44 - 45 - private $type; 46 - private $uri; 47 - 48 - public function __construct($type, $uri) { 49 - switch ($type) { 50 - case self::TYPE_GIT: 51 - case self::TYPE_SVN: 52 - case self::TYPE_MERCURIAL: 53 - break; 54 - default: 55 - throw new Exception(pht('Unknown URI type "%s"!', $type)); 56 - } 57 - 58 - $this->type = $type; 59 - $this->uri = $uri; 60 - } 61 - 62 - public static function getAllURITypes() { 63 - return array( 64 - self::TYPE_GIT, 65 - self::TYPE_SVN, 66 - self::TYPE_MERCURIAL, 67 - ); 68 - } 69 - 70 - 71 - /* -( Normalizing URIs )--------------------------------------------------- */ 72 - 73 - 74 - /** 75 - * @task normal 76 - */ 77 - public function getPath() { 78 - switch ($this->type) { 79 - case self::TYPE_GIT: 80 - $uri = new PhutilURI($this->uri); 81 - return $uri->getPath(); 82 - case self::TYPE_SVN: 83 - case self::TYPE_MERCURIAL: 84 - $uri = new PhutilURI($this->uri); 85 - if ($uri->getProtocol()) { 86 - return $uri->getPath(); 87 - } 88 - 89 - return $this->uri; 90 - } 91 - } 92 - 93 - public function getNormalizedURI() { 94 - return $this->getNormalizedDomain().'/'.$this->getNormalizedPath(); 95 - } 96 - 97 - 98 - /** 99 - * @task normal 100 - */ 101 - public function getNormalizedPath() { 102 - $path = $this->getPath(); 103 - $path = trim($path, '/'); 104 - 105 - switch ($this->type) { 106 - case self::TYPE_GIT: 107 - $path = preg_replace('/\.git$/', '', $path); 108 - break; 109 - case self::TYPE_SVN: 110 - case self::TYPE_MERCURIAL: 111 - break; 112 - } 113 - 114 - // If this is a Phabricator URI, strip it down to the callsign. We mutably 115 - // allow you to clone repositories as "/diffusion/X/anything.git", for 116 - // example. 117 - 118 - $matches = null; 119 - if (preg_match('@^(diffusion/(?:[A-Z]+|\d+))@', $path, $matches)) { 120 - $path = $matches[1]; 121 - } 122 - 123 - return $path; 124 - } 125 - 126 - public function getNormalizedDomain() { 127 - $domain = null; 128 - 129 - $uri = new PhutilURI($this->uri); 130 - $domain = $uri->getDomain(); 131 - 132 - if (!strlen($domain)) { 133 - return '<void>'; 134 - } 135 - 136 - $domain = phutil_utf8_strtolower($domain); 137 - 138 - // See T13435. If the domain for a repository URI is same as the install 139 - // base URI, store it as a "<base-uri>" token instead of the actual domain 140 - // so that the index does not fall out of date if the install moves. 141 - 142 - $base_uri = PhabricatorEnv::getURI('/'); 143 - $base_uri = new PhutilURI($base_uri); 144 - $base_domain = $base_uri->getDomain(); 145 - $base_domain = phutil_utf8_strtolower($base_domain); 146 - if ($domain === $base_domain) { 147 - return '<base-uri>'; 148 - } 149 - 150 - // Likewise, store a token for the "SSH Host" domain so it can be changed 151 - // without requiring an index rebuild. 152 - 153 - $ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host'); 154 - if (strlen($ssh_host)) { 155 - $ssh_host = phutil_utf8_strtolower($ssh_host); 156 - if ($domain === $ssh_host) { 157 - return '<ssh-host>'; 158 - } 159 - } 160 - 161 - return $domain; 162 - } 163 - 164 - 165 - }
-81
src/applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php
··· 1 - <?php 2 - 3 - final class PhabricatorRepositoryURINormalizerTestCase 4 - extends PhabricatorTestCase { 5 - 6 - public function testGitURINormalizer() { 7 - $cases = array( 8 - 'ssh://user@domain.com/path.git' => 'path', 9 - 'https://user@domain.com/path.git' => 'path', 10 - 'git@domain.com:path.git' => 'path', 11 - 'ssh://user@gitserv002.com/path.git' => 'path', 12 - 'ssh://htaft@domain.com/path.git' => 'path', 13 - 'ssh://user@domain.com/bananas.git' => 'bananas', 14 - 'git@domain.com:bananas.git' => 'bananas', 15 - 'user@domain.com:path/repo' => 'path/repo', 16 - 'user@domain.com:path/repo/' => 'path/repo', 17 - 'file:///path/to/local/repo.git' => 'path/to/local/repo', 18 - '/path/to/local/repo.git' => 'path/to/local/repo', 19 - 'ssh://something.com/diffusion/X/anything.git' => 'diffusion/X', 20 - 'ssh://something.com/diffusion/X/' => 'diffusion/X', 21 - ); 22 - 23 - $type_git = PhabricatorRepositoryURINormalizer::TYPE_GIT; 24 - 25 - foreach ($cases as $input => $expect) { 26 - $normal = new PhabricatorRepositoryURINormalizer($type_git, $input); 27 - $this->assertEqual( 28 - $expect, 29 - $normal->getNormalizedPath(), 30 - pht('Normalized Git path for "%s".', $input)); 31 - } 32 - } 33 - 34 - public function testDomainURINormalizer() { 35 - $base_domain = 'base.phabricator.example.com'; 36 - $ssh_domain = 'ssh.phabricator.example.com'; 37 - 38 - $env = PhabricatorEnv::beginScopedEnv(); 39 - $env->overrideEnvConfig('phabricator.base-uri', 'http://'.$base_domain); 40 - $env->overrideEnvConfig('diffusion.ssh-host', $ssh_domain); 41 - 42 - $cases = array( 43 - '/' => '<void>', 44 - '/path/to/local/repo.git' => '<void>', 45 - 'ssh://user@domain.com/path.git' => 'domain.com', 46 - 'ssh://user@DOMAIN.COM/path.git' => 'domain.com', 47 - 'http://'.$base_domain.'/diffusion/X/' => '<base-uri>', 48 - 'ssh://'.$ssh_domain.'/diffusion/X/' => '<ssh-host>', 49 - 'git@'.$ssh_domain.':bananas.git' => '<ssh-host>', 50 - ); 51 - 52 - $type_git = PhabricatorRepositoryURINormalizer::TYPE_GIT; 53 - 54 - foreach ($cases as $input => $expect) { 55 - $normal = new PhabricatorRepositoryURINormalizer($type_git, $input); 56 - 57 - $this->assertEqual( 58 - $expect, 59 - $normal->getNormalizedDomain(), 60 - pht('Normalized domain for "%s".', $input)); 61 - } 62 - } 63 - 64 - public function testSVNURINormalizer() { 65 - $cases = array( 66 - 'file:///path/to/repo' => 'path/to/repo', 67 - 'file:///path/to/repo/' => 'path/to/repo', 68 - ); 69 - 70 - $type_svn = PhabricatorRepositoryURINormalizer::TYPE_SVN; 71 - 72 - foreach ($cases as $input => $expect) { 73 - $normal = new PhabricatorRepositoryURINormalizer($type_svn, $input); 74 - $this->assertEqual( 75 - $expect, 76 - $normal->getNormalizedPath(), 77 - pht('Normalized SVN path for "%s".', $input)); 78 - } 79 - } 80 - 81 - }
+3 -3
src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php
··· 290 290 $remote_root = (string)($xml->entry[0]->repository[0]->root[0]); 291 291 $expect_root = $repository->getSubversionPathURI(); 292 292 293 - $normal_type_svn = PhabricatorRepositoryURINormalizer::TYPE_SVN; 293 + $normal_type_svn = ArcanistRepositoryURINormalizer::TYPE_SVN; 294 294 295 - $remote_normal = id(new PhabricatorRepositoryURINormalizer( 295 + $remote_normal = id(new ArcanistRepositoryURINormalizer( 296 296 $normal_type_svn, 297 297 $remote_root))->getNormalizedPath(); 298 298 299 - $expect_normal = id(new PhabricatorRepositoryURINormalizer( 299 + $expect_normal = id(new ArcanistRepositoryURINormalizer( 300 300 $normal_type_svn, 301 301 $expect_root))->getNormalizedPath(); 302 302
+5 -2
src/applications/repository/query/PhabricatorRepositoryQuery.php
··· 689 689 // or an `svn+ssh` URI, we could deduce how to normalize it. However, this 690 690 // would be more complicated and it's not clear if it matters in practice. 691 691 692 - $types = PhabricatorRepositoryURINormalizer::getAllURITypes(); 692 + $domain_map = PhabricatorRepositoryURI::getURINormalizerDomainMap(); 693 + 694 + $types = ArcanistRepositoryURINormalizer::getAllURITypes(); 693 695 foreach ($this->uris as $uri) { 694 696 foreach ($types as $type) { 695 - $normalized_uri = new PhabricatorRepositoryURINormalizer($type, $uri); 697 + $normalized_uri = new ArcanistRepositoryURINormalizer($type, $uri); 698 + $normalized_uri->setDomainMap($domain_map); 696 699 $normalized_uris[] = $normalized_uri->getNormalizedURI(); 697 700 } 698 701 }
+31 -5
src/applications/repository/storage/PhabricatorRepositoryURI.php
··· 196 196 197 197 $map = array( 198 198 PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 199 - PhabricatorRepositoryURINormalizer::TYPE_GIT, 199 + ArcanistRepositoryURINormalizer::TYPE_GIT, 200 200 PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => 201 - PhabricatorRepositoryURINormalizer::TYPE_SVN, 201 + ArcanistRepositoryURINormalizer::TYPE_SVN, 202 202 PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 203 - PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL, 203 + ArcanistRepositoryURINormalizer::TYPE_MERCURIAL, 204 204 ); 205 205 206 206 $type = $map[$vcs]; 207 207 $display = (string)$this->getDisplayURI(); 208 208 209 - $normal_uri = new PhabricatorRepositoryURINormalizer($type, $display); 209 + $normalizer = new ArcanistRepositoryURINormalizer($type, $display); 210 210 211 - return $normal_uri->getNormalizedURI(); 211 + $domain_map = self::getURINormalizerDomainMap(); 212 + $normalizer->setDomainMap($domain_map); 213 + 214 + return $normalizer->getNormalizedURI(); 212 215 } 213 216 214 217 public function getDisplayURI() { ··· 733 736 734 737 public function getConduitSearchAttachments() { 735 738 return array(); 739 + } 740 + 741 + public static function getURINormalizerDomainMap() { 742 + $domain_map = array(); 743 + 744 + // See T13435. If the domain for a repository URI is same as the install 745 + // base URI, store it as a "<base-uri>" token instead of the actual domain 746 + // so that the index does not fall out of date if the install moves. 747 + 748 + $base_uri = PhabricatorEnv::getURI('/'); 749 + $base_uri = new PhutilURI($base_uri); 750 + $base_domain = $base_uri->getDomain(); 751 + $domain_map['<base-uri>'] = $base_domain; 752 + 753 + // Likewise, store a token for the "SSH Host" domain so it can be changed 754 + // without requiring an index rebuild. 755 + 756 + $ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host'); 757 + if (strlen($ssh_host)) { 758 + $domain_map['<ssh-host>'] = $ssh_host; 759 + } 760 + 761 + return $domain_map; 736 762 } 737 763 738 764 }