diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -4653,8 +4653,6 @@ 'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php', 'PhabricatorRepositoryURI' => 'applications/repository/storage/PhabricatorRepositoryURI.php', 'PhabricatorRepositoryURIIndex' => 'applications/repository/storage/PhabricatorRepositoryURIIndex.php', - 'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php', - 'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php', 'PhabricatorRepositoryURIPHIDType' => 'applications/repository/phid/PhabricatorRepositoryURIPHIDType.php', 'PhabricatorRepositoryURIQuery' => 'applications/repository/query/PhabricatorRepositoryURIQuery.php', 'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php', @@ -11407,8 +11405,6 @@ 'PhabricatorConduitResultInterface', ), 'PhabricatorRepositoryURIIndex' => 'PhabricatorRepositoryDAO', - 'PhabricatorRepositoryURINormalizer' => 'Phobject', - 'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryURIPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryURIQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase', diff --git a/src/applications/repository/data/PhabricatorRepositoryURINormalizer.php b/src/applications/repository/data/PhabricatorRepositoryURINormalizer.php deleted file mode 100644 --- a/src/applications/repository/data/PhabricatorRepositoryURINormalizer.php +++ /dev/null @@ -1,165 +0,0 @@ -getNormalizedPath() == $norm_b->getNormalizedPath()) { - * // URIs appear to point at the same repository. - * } else { - * // URIs are very unlikely to be the same repository. - * } - * - * Because a repository can be hosted at arbitrarily many arbitrary URIs, there - * is no way to completely prevent false negatives by only examining URIs - * (that is, repositories with totally different URIs could really be the same). - * However, normalization is relatively aggressive and false negatives should - * be rare: if normalization says two URIs are different repositories, they - * probably are. - * - * @task normal Normalizing URIs - */ -final class PhabricatorRepositoryURINormalizer extends Phobject { - - const TYPE_GIT = 'git'; - const TYPE_SVN = 'svn'; - const TYPE_MERCURIAL = 'hg'; - - private $type; - private $uri; - - public function __construct($type, $uri) { - switch ($type) { - case self::TYPE_GIT: - case self::TYPE_SVN: - case self::TYPE_MERCURIAL: - break; - default: - throw new Exception(pht('Unknown URI type "%s"!', $type)); - } - - $this->type = $type; - $this->uri = $uri; - } - - public static function getAllURITypes() { - return array( - self::TYPE_GIT, - self::TYPE_SVN, - self::TYPE_MERCURIAL, - ); - } - - -/* -( Normalizing URIs )--------------------------------------------------- */ - - - /** - * @task normal - */ - public function getPath() { - switch ($this->type) { - case self::TYPE_GIT: - $uri = new PhutilURI($this->uri); - return $uri->getPath(); - case self::TYPE_SVN: - case self::TYPE_MERCURIAL: - $uri = new PhutilURI($this->uri); - if ($uri->getProtocol()) { - return $uri->getPath(); - } - - return $this->uri; - } - } - - public function getNormalizedURI() { - return $this->getNormalizedDomain().'/'.$this->getNormalizedPath(); - } - - - /** - * @task normal - */ - public function getNormalizedPath() { - $path = $this->getPath(); - $path = trim($path, '/'); - - switch ($this->type) { - case self::TYPE_GIT: - $path = preg_replace('/\.git$/', '', $path); - break; - case self::TYPE_SVN: - case self::TYPE_MERCURIAL: - break; - } - - // If this is a Phabricator URI, strip it down to the callsign. We mutably - // allow you to clone repositories as "/diffusion/X/anything.git", for - // example. - - $matches = null; - if (preg_match('@^(diffusion/(?:[A-Z]+|\d+))@', $path, $matches)) { - $path = $matches[1]; - } - - return $path; - } - - public function getNormalizedDomain() { - $domain = null; - - $uri = new PhutilURI($this->uri); - $domain = $uri->getDomain(); - - if (!strlen($domain)) { - return ''; - } - - $domain = phutil_utf8_strtolower($domain); - - // See T13435. If the domain for a repository URI is same as the install - // base URI, store it as a "" token instead of the actual domain - // so that the index does not fall out of date if the install moves. - - $base_uri = PhabricatorEnv::getURI('/'); - $base_uri = new PhutilURI($base_uri); - $base_domain = $base_uri->getDomain(); - $base_domain = phutil_utf8_strtolower($base_domain); - if ($domain === $base_domain) { - return ''; - } - - // Likewise, store a token for the "SSH Host" domain so it can be changed - // without requiring an index rebuild. - - $ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host'); - if (strlen($ssh_host)) { - $ssh_host = phutil_utf8_strtolower($ssh_host); - if ($domain === $ssh_host) { - return ''; - } - } - - return $domain; - } - - -} diff --git a/src/applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php b/src/applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php deleted file mode 100644 --- a/src/applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php +++ /dev/null @@ -1,81 +0,0 @@ - 'path', - 'https://user@domain.com/path.git' => 'path', - 'git@domain.com:path.git' => 'path', - 'ssh://user@gitserv002.com/path.git' => 'path', - 'ssh://htaft@domain.com/path.git' => 'path', - 'ssh://user@domain.com/bananas.git' => 'bananas', - 'git@domain.com:bananas.git' => 'bananas', - 'user@domain.com:path/repo' => 'path/repo', - 'user@domain.com:path/repo/' => 'path/repo', - 'file:///path/to/local/repo.git' => 'path/to/local/repo', - '/path/to/local/repo.git' => 'path/to/local/repo', - 'ssh://something.com/diffusion/X/anything.git' => 'diffusion/X', - 'ssh://something.com/diffusion/X/' => 'diffusion/X', - ); - - $type_git = PhabricatorRepositoryURINormalizer::TYPE_GIT; - - foreach ($cases as $input => $expect) { - $normal = new PhabricatorRepositoryURINormalizer($type_git, $input); - $this->assertEqual( - $expect, - $normal->getNormalizedPath(), - pht('Normalized Git path for "%s".', $input)); - } - } - - public function testDomainURINormalizer() { - $base_domain = 'base.phabricator.example.com'; - $ssh_domain = 'ssh.phabricator.example.com'; - - $env = PhabricatorEnv::beginScopedEnv(); - $env->overrideEnvConfig('phabricator.base-uri', 'http://'.$base_domain); - $env->overrideEnvConfig('diffusion.ssh-host', $ssh_domain); - - $cases = array( - '/' => '', - '/path/to/local/repo.git' => '', - 'ssh://user@domain.com/path.git' => 'domain.com', - 'ssh://user@DOMAIN.COM/path.git' => 'domain.com', - 'http://'.$base_domain.'/diffusion/X/' => '', - 'ssh://'.$ssh_domain.'/diffusion/X/' => '', - 'git@'.$ssh_domain.':bananas.git' => '', - ); - - $type_git = PhabricatorRepositoryURINormalizer::TYPE_GIT; - - foreach ($cases as $input => $expect) { - $normal = new PhabricatorRepositoryURINormalizer($type_git, $input); - - $this->assertEqual( - $expect, - $normal->getNormalizedDomain(), - pht('Normalized domain for "%s".', $input)); - } - } - - public function testSVNURINormalizer() { - $cases = array( - 'file:///path/to/repo' => 'path/to/repo', - 'file:///path/to/repo/' => 'path/to/repo', - ); - - $type_svn = PhabricatorRepositoryURINormalizer::TYPE_SVN; - - foreach ($cases as $input => $expect) { - $normal = new PhabricatorRepositoryURINormalizer($type_svn, $input); - $this->assertEqual( - $expect, - $normal->getNormalizedPath(), - pht('Normalized SVN path for "%s".', $input)); - } - } - -} diff --git a/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php b/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php --- a/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php +++ b/src/applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php @@ -290,13 +290,13 @@ $remote_root = (string)($xml->entry[0]->repository[0]->root[0]); $expect_root = $repository->getSubversionPathURI(); - $normal_type_svn = PhabricatorRepositoryURINormalizer::TYPE_SVN; + $normal_type_svn = ArcanistRepositoryURINormalizer::TYPE_SVN; - $remote_normal = id(new PhabricatorRepositoryURINormalizer( + $remote_normal = id(new ArcanistRepositoryURINormalizer( $normal_type_svn, $remote_root))->getNormalizedPath(); - $expect_normal = id(new PhabricatorRepositoryURINormalizer( + $expect_normal = id(new ArcanistRepositoryURINormalizer( $normal_type_svn, $expect_root))->getNormalizedPath(); diff --git a/src/applications/repository/query/PhabricatorRepositoryQuery.php b/src/applications/repository/query/PhabricatorRepositoryQuery.php --- a/src/applications/repository/query/PhabricatorRepositoryQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryQuery.php @@ -689,10 +689,13 @@ // or an `svn+ssh` URI, we could deduce how to normalize it. However, this // would be more complicated and it's not clear if it matters in practice. - $types = PhabricatorRepositoryURINormalizer::getAllURITypes(); + $domain_map = PhabricatorRepositoryURI::getURINormalizerDomainMap(); + + $types = ArcanistRepositoryURINormalizer::getAllURITypes(); foreach ($this->uris as $uri) { foreach ($types as $type) { - $normalized_uri = new PhabricatorRepositoryURINormalizer($type, $uri); + $normalized_uri = new ArcanistRepositoryURINormalizer($type, $uri); + $normalized_uri->setDomainMap($domain_map); $normalized_uris[] = $normalized_uri->getNormalizedURI(); } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryURI.php b/src/applications/repository/storage/PhabricatorRepositoryURI.php --- a/src/applications/repository/storage/PhabricatorRepositoryURI.php +++ b/src/applications/repository/storage/PhabricatorRepositoryURI.php @@ -196,19 +196,22 @@ $map = array( PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => - PhabricatorRepositoryURINormalizer::TYPE_GIT, + ArcanistRepositoryURINormalizer::TYPE_GIT, PhabricatorRepositoryType::REPOSITORY_TYPE_SVN => - PhabricatorRepositoryURINormalizer::TYPE_SVN, + ArcanistRepositoryURINormalizer::TYPE_SVN, PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => - PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL, + ArcanistRepositoryURINormalizer::TYPE_MERCURIAL, ); $type = $map[$vcs]; $display = (string)$this->getDisplayURI(); - $normal_uri = new PhabricatorRepositoryURINormalizer($type, $display); + $normalizer = new ArcanistRepositoryURINormalizer($type, $display); - return $normal_uri->getNormalizedURI(); + $domain_map = self::getURINormalizerDomainMap(); + $normalizer->setDomainMap($domain_map); + + return $normalizer->getNormalizedURI(); } public function getDisplayURI() { @@ -735,4 +738,27 @@ return array(); } + public static function getURINormalizerDomainMap() { + $domain_map = array(); + + // See T13435. If the domain for a repository URI is same as the install + // base URI, store it as a "" token instead of the actual domain + // so that the index does not fall out of date if the install moves. + + $base_uri = PhabricatorEnv::getURI('/'); + $base_uri = new PhutilURI($base_uri); + $base_domain = $base_uri->getDomain(); + $domain_map[''] = $base_domain; + + // Likewise, store a token for the "SSH Host" domain so it can be changed + // without requiring an index rebuild. + + $ssh_host = PhabricatorEnv::getEnvConfig('diffusion.ssh-host'); + if (strlen($ssh_host)) { + $domain_map[''] = $ssh_host; + } + + return $domain_map; + } + }