From e34a44a7ed15cc787b305a1d496f16680e702ff1 Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 25 Jan 2014 14:02:38 -0800 Subject: [PATCH] Allow repository lookup by remote URI Summary: This helps us move away from arcanist projects in normal use, by allowing us to identify repositories based on the remote URI. Test Plan: Used `repository.query` to query some repos by remote URI. Reviewers: btrahan Reviewed By: btrahan CC: aran Differential Revision: https://secure.phabricator.com/D8069 --- .../ConduitAPI_repository_query_Method.php | 6 +++ .../PhabricatorRepositoryURINormalizer.php | 4 ++ .../query/PhabricatorRepositoryQuery.php | 43 +++++++++++++++++++ .../storage/PhabricatorRepository.php | 24 +++++++++++ 4 files changed, 77 insertions(+) diff --git a/src/applications/repository/conduit/ConduitAPI_repository_query_Method.php b/src/applications/repository/conduit/ConduitAPI_repository_query_Method.php index 9ee2512079..c27274ccc6 100644 --- a/src/applications/repository/conduit/ConduitAPI_repository_query_Method.php +++ b/src/applications/repository/conduit/ConduitAPI_repository_query_Method.php @@ -21,6 +21,7 @@ final class ConduitAPI_repository_query_Method 'phids' => 'optional list', 'callsigns' => 'optional list', 'vcsTypes' => 'optional list', + 'remoteURIs' => 'optional list', ); } @@ -57,6 +58,11 @@ final class ConduitAPI_repository_query_Method $query->withTypes($vcs_types); } + $remote_uris = $request->getValue('remoteURIs', array()); + if ($remote_uris) { + $query->withRemoteURIs($remote_uris); + } + $repositories = $query->execute(); $results = array(); diff --git a/src/applications/repository/data/PhabricatorRepositoryURINormalizer.php b/src/applications/repository/data/PhabricatorRepositoryURINormalizer.php index 75714f4f83..403f5e4f38 100644 --- a/src/applications/repository/data/PhabricatorRepositoryURINormalizer.php +++ b/src/applications/repository/data/PhabricatorRepositoryURINormalizer.php @@ -40,6 +40,7 @@ final class PhabricatorRepositoryURINormalizer extends Phobject { const TYPE_GIT = 'git'; const TYPE_SVN = 'svn'; + const TYPE_MERCURIAL = 'hg'; private $type; private $uri; @@ -48,6 +49,7 @@ final class PhabricatorRepositoryURINormalizer extends Phobject { switch ($type) { case self::TYPE_GIT: case self::TYPE_SVN: + case self::TYPE_MERCURIAL: break; default: throw new Exception(pht('Unknown URI type "%s"!')); @@ -79,6 +81,7 @@ final class PhabricatorRepositoryURINormalizer extends Phobject { return $this->uri; case self::TYPE_SVN: + case self::TYPE_MERCURIAL: $uri = new PhutilURI($this->uri); if ($uri->getProtocol()) { return $uri->getPath(); @@ -101,6 +104,7 @@ final class PhabricatorRepositoryURINormalizer extends Phobject { $path = preg_replace('/\.git$/', '', $path); break; case self::TYPE_SVN: + case self::TYPE_MERCURIAL: break; } diff --git a/src/applications/repository/query/PhabricatorRepositoryQuery.php b/src/applications/repository/query/PhabricatorRepositoryQuery.php index 56a03ca181..35bc289c79 100644 --- a/src/applications/repository/query/PhabricatorRepositoryQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryQuery.php @@ -9,6 +9,7 @@ final class PhabricatorRepositoryQuery private $types; private $uuids; private $nameContains; + private $remoteURIs; const STATUS_OPEN = 'status-open'; const STATUS_CLOSED = 'status-closed'; @@ -70,6 +71,11 @@ final class PhabricatorRepositoryQuery return $this; } + public function withRemoteURIs(array $uris) { + $this->remoteURIs = $uris; + return $this; + } + public function needCommitCounts($need_counts) { $this->needCommitCounts = $need_counts; return $this; @@ -90,6 +96,7 @@ final class PhabricatorRepositoryQuery return $this; } + protected function loadPage() { $table = new PhabricatorRepository(); $conn_r = $table->establishConnection('r'); @@ -159,6 +166,7 @@ final class PhabricatorRepositoryQuery throw new Exception("Unknown status '{$status}'!"); } + // TODO: This should also be denormalized. $hosted = $this->hosted; switch ($hosted) { case self::HOSTED_PHABRICATOR: @@ -178,6 +186,17 @@ final class PhabricatorRepositoryQuery } } + // TODO: Denormalize this, too. + if ($this->remoteURIs) { + $try_uris = $this->getNormalizedPaths(); + $try_uris = array_fuse($try_uris); + foreach ($repositories as $key => $repository) { + if (!isset($try_uris[$repository->getNormalizedPath()])) { + unset($repositories[$key]); + } + } + } + return $repositories; } @@ -389,4 +408,28 @@ final class PhabricatorRepositoryQuery return 'PhabricatorApplicationDiffusion'; } + private function getNormalizedPaths() { + $normalized_uris = array(); + + // Since we don't know which type of repository this URI is in the general + // case, just generate all the normalizations. We could refine this in some + // cases: if the query specifies VCS types, or the URI is a git-style URI + // 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. + + foreach ($this->remoteURIs as $uri) { + $normalized_uris[] = new PhabricatorRepositoryURINormalizer( + PhabricatorRepositoryURINormalizer::TYPE_GIT, + $uri); + $normalized_uris[] = new PhabricatorRepositoryURINormalizer( + PhabricatorRepositoryURINormalizer::TYPE_SVN, + $uri); + $normalized_uris[] = new PhabricatorRepositoryURINormalizer( + PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL, + $uri); + } + + return array_unique(mpull($normalized_uris, 'getNormalizedPath')); + } + } diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index 43cf3af929..06aeb21105 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -485,6 +485,30 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO return '/diffusion/'.$this->getCallsign().'/'; } + public function getNormalizedPath() { + switch ($this->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $normalized_uri = new PhabricatorRepositoryURINormalizer( + PhabricatorRepositoryURINormalizer::TYPE_GIT, + $this->getURI()); + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $normalized_uri = new PhabricatorRepositoryURINormalizer( + PhabricatorRepositoryURINormalizer::TYPE_SVN, + $this->getURI()); + break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: + $normalized_uri = new PhabricatorRepositoryURINormalizer( + PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL, + $this->getURI()); + break; + default: + throw new Exception("Unrecognized version control system."); + } + + return $normalized_uri->getNormalizedPath(); + } + public function isTracked() { return $this->getDetail('tracking-enabled', false); }