From 50f7a853b5cf8f33ef3dfc21693ad5b375af2f80 Mon Sep 17 00:00:00 2001 From: epriestley Date: Tue, 30 Jun 2020 13:03:20 -0700 Subject: [PATCH] Load and map repository objects for remote URIs Summary: Ref T13546. Query and associate known Phabricator repositories to working copy remotes by normalizing and comparing URIs. This primarily gives us access to "permanentRefRules" so we can tell which branches have published changes. Test Plan: Ran "arc look remotes" in Git and Mercurial working copies, saw repositories map properly. Maniphest Tasks: T13546 Differential Revision: https://secure.phabricator.com/D21377 --- src/__phutil_library_map__.php | 2 + src/ref/ArcanistRepositoryRef.php | 42 ++++++++- src/repository/api/ArcanistGitAPI.php | 6 ++ src/repository/api/ArcanistMercurialAPI.php | 6 ++ src/repository/api/ArcanistRepositoryAPI.php | 9 ++ src/repository/remote/ArcanistRemoteRef.php | 47 ++++++++++ ...nistRemoteRepositoryRefsHardpointQuery.php | 89 +++++++++++++++++++ .../remote/ArcanistRepositoryRemoteQuery.php | 5 ++ src/workflow/ArcanistLookWorkflow.php | 29 ++++++ 9 files changed, 232 insertions(+), 3 deletions(-) create mode 100644 src/repository/remote/ArcanistRemoteRepositoryRefsHardpointQuery.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 12416504..d43615b1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -422,6 +422,7 @@ phutil_register_library_map(array( 'ArcanistRefView' => 'ref/ArcanistRefView.php', 'ArcanistRemoteRef' => 'repository/remote/ArcanistRemoteRef.php', 'ArcanistRemoteRefInspector' => 'repository/remote/ArcanistRemoteRefInspector.php', + 'ArcanistRemoteRepositoryRefsHardpointQuery' => 'repository/remote/ArcanistRemoteRepositoryRefsHardpointQuery.php', 'ArcanistRepositoryAPI' => 'repository/api/ArcanistRepositoryAPI.php', 'ArcanistRepositoryAPIMiscTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIMiscTestCase.php', 'ArcanistRepositoryAPIStateTestCase' => 'repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php', @@ -1455,6 +1456,7 @@ phutil_register_library_map(array( ), 'ArcanistRemoteRef' => 'ArcanistRef', 'ArcanistRemoteRefInspector' => 'ArcanistRefInspector', + 'ArcanistRemoteRepositoryRefsHardpointQuery' => 'ArcanistRuntimeHardpointQuery', 'ArcanistRepositoryAPI' => 'Phobject', 'ArcanistRepositoryAPIMiscTestCase' => 'PhutilTestCase', 'ArcanistRepositoryAPIStateTestCase' => 'PhutilTestCase', diff --git a/src/ref/ArcanistRepositoryRef.php b/src/ref/ArcanistRepositoryRef.php index e7e7a2ee..ffbe52fb 100644 --- a/src/ref/ArcanistRepositoryRef.php +++ b/src/ref/ArcanistRepositoryRef.php @@ -3,6 +3,7 @@ final class ArcanistRepositoryRef extends ArcanistRef { + private $parameters = array(); private $phid; private $browseURI; @@ -24,6 +25,37 @@ final class ArcanistRepositoryRef return $this; } + public static function newFromConduit(array $map) { + $ref = new self(); + $ref->parameters = $map; + + $ref->phid = $map['phid']; + + return $ref; + } + + public function getURIs() { + $uris = idxv($this->parameters, array('attachments', 'uris', 'uris')); + + if (!$uris) { + return array(); + } + + $results = array(); + foreach ($uris as $uri) { + $effective_uri = idxv($uri, array('fields', 'uri', 'effective')); + if ($effective_uri !== null) { + $results[] = $effective_uri; + } + } + + return $results; + } + + public function getDisplayName() { + return idxv($this->parameters, array('fields', 'name')); + } + public function newBrowseURI(array $params) { PhutilTypeSpec::checkMap( $params, @@ -67,9 +99,13 @@ final class ArcanistRepositoryRef } public function getDefaultBranch() { - // TODO: This should read from the remote, and is not correct for - // Mercurial anyway, as "default" would be a better default branch. - return 'master'; + $branch = idxv($this->parameters, array('fields', 'defaultBranch')); + + if ($branch === null) { + return 'master'; + } + + return $branch; } } diff --git a/src/repository/api/ArcanistGitAPI.php b/src/repository/api/ArcanistGitAPI.php index ebd2d1d9..5b5c56cc 100644 --- a/src/repository/api/ArcanistGitAPI.php +++ b/src/repository/api/ArcanistGitAPI.php @@ -1767,4 +1767,10 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI { return new ArcanistGitRepositoryRemoteQuery(); } + protected function newNormalizedURI($uri) { + return new ArcanistRepositoryURINormalizer( + ArcanistRepositoryURINormalizer::TYPE_GIT, + $uri); + } + } diff --git a/src/repository/api/ArcanistMercurialAPI.php b/src/repository/api/ArcanistMercurialAPI.php index fdb5e1e0..a24cb13f 100644 --- a/src/repository/api/ArcanistMercurialAPI.php +++ b/src/repository/api/ArcanistMercurialAPI.php @@ -1025,4 +1025,10 @@ final class ArcanistMercurialAPI extends ArcanistRepositoryAPI { ); } + protected function newNormalizedURI($uri) { + return new ArcanistRepositoryURINormalizer( + ArcanistRepositoryURINormalizer::TYPE_MERCURIAL, + $uri); + } + } diff --git a/src/repository/api/ArcanistRepositoryAPI.php b/src/repository/api/ArcanistRepositoryAPI.php index 070fd085..79052eaa 100644 --- a/src/repository/api/ArcanistRepositoryAPI.php +++ b/src/repository/api/ArcanistRepositoryAPI.php @@ -798,4 +798,13 @@ abstract class ArcanistRepositoryAPI extends Phobject { return substr($hash, 0, 12); } + final public function getNormalizedURI($uri) { + $normalized_uri = $this->newNormalizedURI($uri); + return $normalized_uri->getNormalizedURI(); + } + + protected function newNormalizedURI($uri) { + return $uri; + } + } diff --git a/src/repository/remote/ArcanistRemoteRef.php b/src/repository/remote/ArcanistRemoteRef.php index 40092798..aea02147 100644 --- a/src/repository/remote/ArcanistRemoteRef.php +++ b/src/repository/remote/ArcanistRemoteRef.php @@ -3,14 +3,26 @@ final class ArcanistRemoteRef extends ArcanistRef { + private $repositoryAPI; private $remoteName; private $fetchURI; private $pushURI; + const HARDPOINT_REPOSITORYREFS = 'arc.remote.repositoryRefs'; + public function getRefDisplayName() { return pht('Remote "%s"', $this->getRemoteName()); } + public function setRepositoryAPI(ArcanistRepositoryAPI $repository_api) { + $this->repositoryAPI = $repository_api; + return $this; + } + + public function getRepositoryAPI() { + return $this->repositoryAPI; + } + public function setRemoteName($remote_name) { $this->remoteName = $remote_name; return $this; @@ -42,4 +54,39 @@ final class ArcanistRemoteRef $view->setObjectName($this->getRemoteName()); } + protected function newHardpoints() { + $object_list = new ArcanistObjectListHardpoint(); + return array( + $this->newTemplateHardpoint(self::HARDPOINT_REPOSITORYREFS, $object_list), + ); + } + + private function getRepositoryRefs() { + return $this->getHardpoint(self::HARDPOINT_REPOSITORYREFS); + } + + public function getPushRepositoryRef() { + return $this->getRepositoryRefByURI($this->getPushURI()); + } + + public function getFetchRepositoryRef() { + return $this->getRepositoryRefByURI($this->getFetchURI()); + } + + private function getRepositoryRefByURI($uri) { + $api = $this->getRepositoryAPI(); + + $uri = $api->getNormalizedURI($uri); + foreach ($this->getRepositoryRefs() as $repository_ref) { + foreach ($repository_ref->getURIs() as $repository_uri) { + $repository_uri = $api->getNormalizedURI($repository_uri); + if ($repository_uri === $uri) { + return $repository_ref; + } + } + } + + return null; + } + } diff --git a/src/repository/remote/ArcanistRemoteRepositoryRefsHardpointQuery.php b/src/repository/remote/ArcanistRemoteRepositoryRefsHardpointQuery.php new file mode 100644 index 00000000..9969203f --- /dev/null +++ b/src/repository/remote/ArcanistRemoteRepositoryRefsHardpointQuery.php @@ -0,0 +1,89 @@ +getRepositoryAPI(); + + $uris = array(); + foreach ($refs as $remote) { + $fetch_uri = $remote->getFetchURI(); + if ($fetch_uri !== null) { + $uris[] = $fetch_uri; + } + + $push_uri = $remote->getPushURI(); + if ($push_uri !== null) { + $uris[] = $push_uri; + } + } + + if (!$uris) { + yield $this->yieldValue($refs, array()); + } + + $uris = array_fuse($uris); + $uris = array_values($uris); + + $search_future = $this->newConduitSearch( + 'diffusion.repository.search', + array( + 'uris' => $uris, + ), + array( + 'uris' => true, + )); + + $repository_info = (yield $this->yieldFuture($search_future)); + + $repository_refs = array(); + foreach ($repository_info as $raw_result) { + $repository_refs[] = ArcanistRepositoryRef::newFromConduit($raw_result); + } + + $uri_map = array(); + foreach ($repository_refs as $repository_ref) { + foreach ($repository_ref->getURIs() as $repository_uri) { + $repository_uri = $api->getNormalizedURI($repository_uri); + $uri_map[$repository_uri] = $repository_ref; + } + } + + $results = array(); + foreach ($refs as $key => $remote) { + $result = array(); + + $fetch_uri = $remote->getFetchURI(); + if ($fetch_uri !== null) { + $fetch_uri = $api->getNormalizedURI($fetch_uri); + if (isset($uri_map[$fetch_uri])) { + $result[] = $uri_map[$fetch_uri]; + } + } + + $push_uri = $remote->getPushURI(); + if ($push_uri !== null) { + $push_uri = $api->getNormalizedURI($push_uri); + if (isset($uri_map[$push_uri])) { + $result[] = $uri_map[$push_uri]; + } + } + + $results[$key] = $result; + } + + yield $this->yieldMap($results); + } + +} diff --git a/src/repository/remote/ArcanistRepositoryRemoteQuery.php b/src/repository/remote/ArcanistRepositoryRemoteQuery.php index cff6a185..9918f2ac 100644 --- a/src/repository/remote/ArcanistRepositoryRemoteQuery.php +++ b/src/repository/remote/ArcanistRepositoryRemoteQuery.php @@ -11,8 +11,13 @@ abstract class ArcanistRepositoryRemoteQuery } final public function execute() { + $api = $this->getRepositoryAPI(); $refs = $this->newRemoteRefs(); + foreach ($refs as $ref) { + $ref->setRepositoryAPI($api); + } + $names = $this->names; if ($names !== null) { $names = array_fuse($names); diff --git a/src/workflow/ArcanistLookWorkflow.php b/src/workflow/ArcanistLookWorkflow.php index 58e23e35..d4f25022 100644 --- a/src/workflow/ArcanistLookWorkflow.php +++ b/src/workflow/ArcanistLookWorkflow.php @@ -140,6 +140,11 @@ EOTEXT $remotes = $api->newRemoteRefQuery() ->execute(); + + $this->loadHardpoints( + $remotes, + ArcanistRemoteRef::HARDPOINT_REPOSITORYREFS); + foreach ($remotes as $remote) { $view = $remote->newRefView(); @@ -154,6 +159,18 @@ EOTEXT 'Push URI: %s', $push_uri)); + $push_repository = $remote->getPushRepositoryRef(); + if ($push_repository) { + $push_display = $push_repository->getDisplayName(); + } else { + $push_display = '-'; + } + + $view->appendLine( + pht( + 'Push Repository: %s', + $push_display)); + $fetch_uri = $remote->getFetchURI(); if ($fetch_uri === null) { $fetch_uri = '-'; @@ -164,6 +181,18 @@ EOTEXT 'Fetch URI: %s', $fetch_uri)); + $fetch_repository = $remote->getFetchRepositoryRef(); + if ($fetch_repository) { + $fetch_display = $fetch_repository->getDisplayName(); + } else { + $fetch_display = '-'; + } + + $view->appendLine( + pht( + 'Fetch Repository: %s', + $fetch_display)); + echo tsprintf('%s', $view); } }