diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index 2257777b61..d82ec3b5bc 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -16,6 +16,9 @@ * limitations under the License. */ +/** + * @task uri Repository URI Management + */ final class PhabricatorRepository extends PhabricatorRepositoryDAO { const TABLE_PATH = 'repository_path'; @@ -70,41 +73,6 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO { )); } - public function getRemoteURI() { - $raw_uri = $this->getDetail('remote-uri'); - if (!$raw_uri) { - return null; - } - - if (strpos($raw_uri, '/') === 0) { - // If the URI starts with a '/', it's an implicit file:// URI on the - // local disk. - $uri = new PhutilURI('file://'.$raw_uri); - return (string)$uri; - } - - $uri = new PhutilURI($raw_uri); - if ($uri->getProtocol()) { - if ($this->isSSHProtocol($uri->getProtocol())) { - if ($this->getSSHLogin()) { - $uri->setUser($this->getSSHLogin()); - } - } - return (string)$uri; - } - - $uri = new PhutilGitURI($raw_uri); - if ($uri->getDomain()) { - if ($this->getSSHLogin()) { - $uri->setUser($this->getSSHLogin()); - } - return (string)$uri; - } - - throw new Exception( - "Repository remote URI '{$raw_uri}' could not be parsed!"); - } - public function getLocalPath() { return $this->getDetail('local-path'); } @@ -308,64 +276,10 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO { return (string)$this->sshKeyfile; } - public function shouldUseSSH() { - $uri = new PhutilURI($this->getRemoteURI()); - $protocol = $uri->getProtocol(); - if ($this->isSSHProtocol($protocol)) { - return (bool)$this->getSSHKeyfile(); - } else { - return false; - } - } - - public function shouldUseHTTP() { - $uri = new PhutilURI($this->getRemoteURI()); - $protocol = $uri->getProtocol(); - if ($this->isHTTPProtocol($protocol)) { - return (bool)$this->getDetail('http-login'); - } else { - return false; - } - } - - public function shouldUseSVNProtocol() { - $uri = new PhutilURI($this->getRemoteURI()); - $protocol = $uri->getProtocol(); - if ($this->isSVNProtocol($protocol)) { - return (bool)$this->getDetail('http-login'); - } else { - return false; - } - } - - - public function getPublicRemoteURI() { - $uri = new PhutilURI($this->getRemoteURI()); - - // Make sure we don't leak anything if this repo is using HTTP Basic Auth - // with the credentials in the URI or something zany like that. - $uri->setUser(null); - $uri->setPass(null); - - return $uri; - } - public function getURI() { return '/diffusion/'.$this->getCallsign().'/'; } - private function isSSHProtocol($protocol) { - return ($protocol == 'ssh' || $protocol == 'svn+ssh'); - } - - private function isHTTPProtocol($protocol) { - return ($protocol == 'http' || $protocol == 'https'); - } - - private function isSVNProtocol($protocol) { - return ($protocol == 'svn'); - } - public function isTracked() { return $this->getDetail('tracking-enabled', false); } @@ -476,4 +390,160 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO { return $repositories; } +/* -( Repository URI Management )------------------------------------------ */ + + + /** + * Get the remote URI for this repository. + * + * @return string + * @task uri + */ + public function getRemoteURI() { + return (string)$this->getRemoteURIObject(); + } + + + /** + * Get the remote URI for this repository, without authentication information. + * + * @return string Repository URI. + * @task uri + */ + public function getPublicRemoteURI() { + $uri = $this->getURIObject(); + + // Make sure we don't leak anything if this repo is using HTTP Basic Auth + // with the credentials in the URI or something zany like that. + + if ($uri instanceof PhutilGitURI) { + $uri->setUser(null); + } else { + $uri->setUser(null); + $uri->setPass(null); + } + + return (string)$uri; + } + + + /** + * Get the protocol for the repository's remote. + * + * @return string Protocol, like "ssh" or "git". + * @task uri + */ + public function getRemoteProtocol() { + $uri = $this->getRemoteURIObject(); + + if ($uri instanceof PhutilGitURI) { + return 'ssh'; + } else { + return $uri->getProtocol(); + } + } + + + /** + * Get a parsed object representation of the repository's remote URI. This + * may be a normal URI (returned as a @{class:PhutilURI}) or a git URI + * (returned as a @{class:PhutilGitURI}). + * + * @return wild A @{class:PhutilURI} or @{class:PhutilGitURI}. + * @task uri + */ + private function getRemoteURIObject() { + $raw_uri = $this->getDetail('remote-uri'); + if (!$raw_uri) { + return new PhutilURI(''); + } + + if (!strncmp($raw_uri, '/', 1)) { + return new PhutilURI('file://'.$raw_uri); + } + + $uri = new PhutilURI($raw_uri); + if ($uri->getProtocol()) { + if ($this->isSSHProtocol($uri->getProtocol())) { + if ($this->getSSHLogin()) { + $uri->setUser($this->getSSHLogin()); + } + } + return $uri; + } + + $uri = new PhutilGitURI($raw_uri); + if ($uri->getDomain()) { + if ($this->getSSHLogin()) { + $uri->setUser($this->getSSHLogin()); + } + return $uri; + } + + throw new Exception("Remote URI '{$raw_uri}' could not be parsed!"); + } + + + /** + * Determine if we should connect to the remote using SSH flags and + * credentials. + * + * @return bool True to use the SSH protocol. + * @task uri + */ + private function shouldUseSSH() { + $protocol = $this->getRemoteProtocol(); + if ($this->isSSHProtocol($protocol)) { + return (bool)$this->getSSHKeyfile(); + } else { + return false; + } + } + + + /** + * Determine if we should connect to the remote using HTTP flags and + * credentials. + * + * @return bool True to use the HTTP protocol. + * @task uri + */ + private function shouldUseHTTP() { + $protocol = $this->getRemoteProtocol(); + if ($protocol == 'http' || $protocol == 'https') { + return (bool)$this->getDetail('http-login'); + } else { + return false; + } + } + + + /** + * Determine if we should connect to the remote using SVN flags and + * credentials. + * + * @return bool True to use the SVN protocol. + * @task uri + */ + private function shouldUseSVNProtocol() { + $protocol = $this->getRemoteProtocol(); + if ($protocol == 'svn') { + return (bool)$this->getDetail('http-login'); + } else { + return false; + } + } + + + /** + * Determine if a protocol is SSH or SSH-like. + * + * @param string A protocol string, like "http" or "ssh". + * @return bool True if the protocol is SSH-like. + * @task uri + */ + private function isSSHProtocol($protocol) { + return ($protocol == 'ssh' || $protocol == 'svn+ssh'); + } + } diff --git a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php index 6b8d3672b0..7456ed92e4 100644 --- a/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php +++ b/src/applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php @@ -19,6 +19,30 @@ final class PhabricatorRepositoryTestCase extends PhabricatorTestCase { + public function testRepositoryURIProtocols() { + $tests = array( + '/path/to/repo' => 'file', + 'file:///path/to/repo' => 'file', + 'ssh://user@domain.com/path' => 'ssh', + 'git@example.com:path' => 'ssh', + 'git://git@example.com/path' => 'git', + 'svn+ssh://example.com/path' => 'svn+ssh', + 'https://example.com/repo/' => 'https', + 'http://example.com/' => 'http', + 'https://user@example.com/' => 'https', + ); + + foreach ($tests as $uri => $expect) { + $repository = new PhabricatorRepository(); + $repository->setDetail('remote-uri', $uri); + + $this->assertEqual( + $expect, + $repository->getRemoteProtocol(), + "Protocol for '{$uri}'."); + } + } + public function testBranchFilter() { $git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT;