diff --git a/src/applications/repository/query/PhabricatorRepositoryQuery.php b/src/applications/repository/query/PhabricatorRepositoryQuery.php index dad3595745..56a03ca181 100644 --- a/src/applications/repository/query/PhabricatorRepositoryQuery.php +++ b/src/applications/repository/query/PhabricatorRepositoryQuery.php @@ -1,364 +1,392 @@ ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withCallsigns(array $callsigns) { $this->callsigns = $callsigns; return $this; } public function withStatus($status) { $this->status = $status; return $this; } + public function withHosted($hosted) { + $this->hosted = $hosted; + return $this; + } + public function withTypes(array $types) { $this->types = $types; return $this; } public function withUUIDs(array $uuids) { $this->uuids = $uuids; return $this; } public function withNameContains($contains) { $this->nameContains = $contains; return $this; } public function needCommitCounts($need_counts) { $this->needCommitCounts = $need_counts; return $this; } public function needMostRecentCommits($need_commits) { $this->needMostRecentCommits = $need_commits; return $this; } public function needProjectPHIDs($need_phids) { $this->needProjectPHIDs = $need_phids; return $this; } public function setOrder($order) { $this->order = $order; return $this; } protected function loadPage() { $table = new PhabricatorRepository(); $conn_r = $table->establishConnection('r'); $data = queryfx_all( $conn_r, 'SELECT * FROM %T r %Q %Q %Q %Q', $table->getTableName(), $this->buildJoinsClause($conn_r), $this->buildWhereClause($conn_r), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); $repositories = $table->loadAllFromArray($data); if ($this->needCommitCounts) { $sizes = ipull($data, 'size', 'id'); foreach ($repositories as $id => $repository) { $repository->attachCommitCount(nonempty($sizes[$id], 0)); } } if ($this->needMostRecentCommits) { $commit_ids = ipull($data, 'lastCommitID', 'id'); $commit_ids = array_filter($commit_ids); if ($commit_ids) { $commits = id(new DiffusionCommitQuery()) ->setViewer($this->getViewer()) ->withIDs($commit_ids) ->execute(); } else { $commits = array(); } foreach ($repositories as $id => $repository) { $commit = null; if (idx($commit_ids, $id)) { $commit = idx($commits, $commit_ids[$id]); } $repository->attachMostRecentCommit($commit); } } return $repositories; } public function willFilterPage(array $repositories) { assert_instances_of($repositories, 'PhabricatorRepository'); // TODO: Denormalize repository status into the PhabricatorRepository // table so we can do this filtering in the database. foreach ($repositories as $key => $repo) { $status = $this->status; switch ($status) { case self::STATUS_OPEN: if (!$repo->isTracked()) { unset($repositories[$key]); } break; case self::STATUS_CLOSED: if ($repo->isTracked()) { unset($repositories[$key]); } break; case self::STATUS_ALL: break; default: throw new Exception("Unknown status '{$status}'!"); } + + $hosted = $this->hosted; + switch ($hosted) { + case self::HOSTED_PHABRICATOR: + if (!$repo->isHosted()) { + unset($repositories[$key]); + } + break; + case self::HOSTED_REMOTE: + if ($repo->isHosted()) { + unset($repositories[$key]); + } + break; + case self::HOSTED_ALL: + break; + default: + throw new Exception("Uknown hosted failed '${hosted}'!"); + } } return $repositories; } public function didFilterPage(array $repositories) { if ($this->needProjectPHIDs) { $type_project = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_PROJECT; $edge_query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(mpull($repositories, 'getPHID')) ->withEdgeTypes(array($type_project)); $edge_query->execute(); foreach ($repositories as $repository) { $project_phids = $edge_query->getDestinationPHIDs( array( $repository->getPHID(), )); $repository->attachProjectPHIDs($project_phids); } } return $repositories; } public function getReversePaging() { switch ($this->order) { case self::ORDER_CALLSIGN: case self::ORDER_NAME: return true; } return false; } protected function getPagingColumn() { $order = $this->order; switch ($order) { case self::ORDER_CREATED: return 'r.id'; case self::ORDER_COMMITTED: return 's.epoch'; case self::ORDER_CALLSIGN: return 'r.callsign'; case self::ORDER_NAME: return 'r.name'; default: throw new Exception("Unknown order '{$order}!'"); } } private function loadCursorObject($id) { $query = id(new PhabricatorRepositoryQuery()) ->setViewer($this->getPagingViewer()) ->withIDs(array((int)$id)); if ($this->order == self::ORDER_COMMITTED) { $query->needMostRecentCommits(true); } $results = $query->execute(); return head($results); } protected function buildPagingClause(AphrontDatabaseConnection $conn_r) { $default = parent::buildPagingClause($conn_r); $before_id = $this->getBeforeID(); $after_id = $this->getAfterID(); if (!$before_id && !$after_id) { return $default; } $order = $this->order; if ($order == self::ORDER_CREATED) { return $default; } if ($before_id) { $cursor = $this->loadCursorObject($before_id); } else { $cursor = $this->loadCursorObject($after_id); } if (!$cursor) { return null; } $id_column = array( 'name' => 'r.id', 'type' => 'int', 'value' => $cursor->getID(), ); $columns = array(); switch ($order) { case self::ORDER_COMMITTED: $commit = $cursor->getMostRecentCommit(); if (!$commit) { return null; } $columns[] = array( 'name' => 's.epoch', 'type' => 'int', 'value' => $commit->getEpoch(), ); $columns[] = $id_column; break; case self::ORDER_CALLSIGN: $columns[] = array( 'name' => 'r.callsign', 'type' => 'string', 'value' => $cursor->getCallsign(), 'reverse' => true, ); break; case self::ORDER_NAME: $columns[] = array( 'name' => 'r.name', 'type' => 'string', 'value' => $cursor->getName(), 'reverse' => true, ); $columns[] = $id_column; break; default: throw new Exception("Unknown order '{$order}'!"); } return $this->buildPagingClauseFromMultipleColumns( $conn_r, $columns, array( // TODO: Clean up the column ordering stuff and then make this // depend on getReversePaging(). 'reversed' => (bool)($before_id), )); } private function buildJoinsClause(AphrontDatabaseConnection $conn_r) { $joins = array(); $join_summary_table = $this->needCommitCounts || $this->needMostRecentCommits || ($this->order == self::ORDER_COMMITTED); if ($join_summary_table) { $joins[] = qsprintf( $conn_r, 'LEFT JOIN %T s ON r.id = s.repositoryID', PhabricatorRepository::TABLE_SUMMARY); } return implode(' ', $joins); } private function buildWhereClause(AphrontDatabaseConnection $conn_r) { $where = array(); if ($this->ids) { $where[] = qsprintf( $conn_r, 'r.id IN (%Ld)', $this->ids); } if ($this->phids) { $where[] = qsprintf( $conn_r, 'r.phid IN (%Ls)', $this->phids); } if ($this->callsigns) { $where[] = qsprintf( $conn_r, 'r.callsign IN (%Ls)', $this->callsigns); } if ($this->types) { $where[] = qsprintf( $conn_r, 'r.versionControlSystem IN (%Ls)', $this->types); } if ($this->uuids) { $where[] = qsprintf( $conn_r, 'r.uuid IN (%Ls)', $this->uuids); } if (strlen($this->nameContains)) { $where[] = qsprintf( $conn_r, 'name LIKE %~', $this->nameContains); } $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); } public function getQueryApplicationClass() { return 'PhabricatorApplicationDiffusion'; } } diff --git a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php index 98fb1af778..3d6a422778 100644 --- a/src/applications/repository/query/PhabricatorRepositorySearchEngine.php +++ b/src/applications/repository/query/PhabricatorRepositorySearchEngine.php @@ -1,168 +1,196 @@ setParameter('callsigns', $request->getStrList('callsigns')); $saved->setParameter('status', $request->getStr('status')); $saved->setParameter('order', $request->getStr('order')); + $saved->setParameter('hosted', $request->getStr('hosted')); $saved->setParameter('types', $request->getArr('types')); $saved->setParameter('name', $request->getStr('name')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new PhabricatorRepositoryQuery()) ->needProjectPHIDs(true) ->needCommitCounts(true) ->needMostRecentCommits(true); $callsigns = $saved->getParameter('callsigns'); if ($callsigns) { $query->withCallsigns($callsigns); } $status = $saved->getParameter('status'); $status = idx($this->getStatusValues(), $status); if ($status) { $query->withStatus($status); } $order = $saved->getParameter('order'); $order = idx($this->getOrderValues(), $order); if ($order) { $query->setOrder($order); } else { $query->setOrder(head($this->getOrderValues())); } + $hosted = $saved->getParameter('hosted'); + $hosted = idx($this->getHostedValues(), $hosted); + if ($hosted) { + $query->withHosted($hosted); + } + $types = $saved->getParameter('types'); if ($types) { $query->withTypes($types); } $name = $saved->getParameter('name'); if (strlen($name)) { $query->withNameContains($name); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved_query) { $callsigns = $saved_query->getParameter('callsigns', array()); $types = $saved_query->getParameter('types', array()); $types = array_fuse($types); $name = $saved_query->getParameter('name'); $form ->appendChild( id(new AphrontFormTextControl()) ->setName('callsigns') ->setLabel(pht('Callsigns')) ->setValue(implode(', ', $callsigns))) ->appendChild( id(new AphrontFormTextControl()) ->setName('name') ->setLabel(pht('Name Contains')) ->setValue($name)) ->appendChild( id(new AphrontFormSelectControl()) ->setName('status') ->setLabel(pht('Status')) ->setValue($saved_query->getParameter('status')) - ->setOptions($this->getStatusOptions())); + ->setOptions($this->getStatusOptions())) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setName('hosted') + ->setLabel(pht('Hosted')) + ->setValue($saved_query->getParameter('hosted')) + ->setOptions($this->getHostedOptions())); $type_control = id(new AphrontFormCheckboxControl()) ->setLabel(pht('Types')); $all_types = PhabricatorRepositoryType::getAllRepositoryTypes(); foreach ($all_types as $key => $name) { $type_control->addCheckbox( 'types[]', $key, $name, isset($types[$key])); } $form ->appendChild($type_control) ->appendChild( id(new AphrontFormSelectControl()) ->setName('order') ->setLabel(pht('Order')) ->setValue($saved_query->getParameter('order')) ->setOptions($this->getOrderOptions())); } protected function getURI($path) { return '/diffusion/'.$path; } public function getBuiltinQueryNames() { $names = array( 'active' => pht('Active Repositories'), 'all' => pht('All Repositories'), ); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'active': return $query->setParameter('status', 'open'); case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } private function getStatusOptions() { return array( '' => pht('Active and Inactive Repositories'), 'open' => pht('Active Repositories'), 'closed' => pht('Inactive Repositories'), ); } private function getStatusValues() { return array( '' => PhabricatorRepositoryQuery::STATUS_ALL, 'open' => PhabricatorRepositoryQuery::STATUS_OPEN, 'closed' => PhabricatorRepositoryQuery::STATUS_CLOSED, ); } private function getOrderOptions() { return array( 'committed' => pht('Most Recent Commit'), 'name' => pht('Name'), 'callsign' => pht('Callsign'), 'created' => pht('Date Created'), ); } private function getOrderValues() { return array( 'committed' => PhabricatorRepositoryQuery::ORDER_COMMITTED, 'name' => PhabricatorRepositoryQuery::ORDER_NAME, 'callsign' => PhabricatorRepositoryQuery::ORDER_CALLSIGN, 'created' => PhabricatorRepositoryQuery::ORDER_CREATED, ); } + private function getHostedOptions() { + return array( + '' => pht('Hosted and Remote Repositories'), + 'phabricator' => pht('Hosted Repositories'), + 'remote' => pht('Remote Repositories'), + ); + } + + private function getHostedValues() { + return array( + '' => PhabricatorRepositoryQuery::HOSTED_ALL, + 'phabricator' => PhabricatorRepositoryQuery::HOSTED_PHABRICATOR, + 'remote' => PhabricatorRepositoryQuery::HOSTED_REMOTE, + ); + } }