From 4b91c4f7ae91e094b365efec5a553a64493ec733 Mon Sep 17 00:00:00 2001 From: epriestley Date: Fri, 22 Nov 2013 15:23:50 -0800 Subject: [PATCH] Add UI for defining repository mirrors Summary: Ref T4038. This adds everything except the actual pushing part for mirrors. This isn't the most beautiful or sophisticated UI, but I want get the authoritative repositories self-hosted and get users beta-ing hosting as soon as possible. We can do transactions, etc., later on. Test Plan: See screenshots. Reviewers: btrahan Reviewed By: btrahan CC: aran Maniphest Tasks: T4038 Differential Revision: https://secure.phabricator.com/D7632 --- resources/sql/patches/20131122.repomirror.sql | 13 ++ src/__phutil_library_map__.php | 14 ++ .../PhabricatorApplicationDiffusion.php | 4 + .../DiffusionMirrorDeleteController.php | 47 +++++ .../DiffusionMirrorEditController.php | 121 +++++++++++++ .../DiffusionRepositoryEditMainController.php | 169 +++++++++++++++--- .../view/PassphraseCredentialControl.php | 22 ++- .../PhabricatorRepositoryPHIDTypeMirror.php | 47 +++++ .../PhabricatorRepositoryMirrorQuery.php | 101 +++++++++++ .../storage/PhabricatorRepository.php | 17 ++ .../storage/PhabricatorRepositoryMirror.php | 60 +++++++ .../patch/PhabricatorBuiltinPatchList.php | 4 + 12 files changed, 584 insertions(+), 35 deletions(-) create mode 100644 resources/sql/patches/20131122.repomirror.sql create mode 100644 src/applications/diffusion/controller/DiffusionMirrorDeleteController.php create mode 100644 src/applications/diffusion/controller/DiffusionMirrorEditController.php create mode 100644 src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php create mode 100644 src/applications/repository/query/PhabricatorRepositoryMirrorQuery.php create mode 100644 src/applications/repository/storage/PhabricatorRepositoryMirror.php diff --git a/resources/sql/patches/20131122.repomirror.sql b/resources/sql/patches/20131122.repomirror.sql new file mode 100644 index 0000000000..38d2bd55f9 --- /dev/null +++ b/resources/sql/patches/20131122.repomirror.sql @@ -0,0 +1,13 @@ +CREATE TABLE {$NAMESPACE}_repository.repository_mirror ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + phid VARCHAR(64) NOT NULL COLLATE utf8_bin, + repositoryPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + remoteURI VARCHAR(255) NOT NULL COLLATE utf8_bin, + credentialPHID VARCHAR(64) COLLATE utf8_bin, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + + UNIQUE KEY `key_phid` (phid), + KEY `key_repository` (repositoryPHID) + +) ENGINE=InnoDB, COLLATE utf8_general_ci; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 00a543804b..3c03eed019 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -510,6 +510,8 @@ phutil_register_library_map(array( 'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php', 'DiffusionMercurialResponse' => 'applications/diffusion/response/DiffusionMercurialResponse.php', 'DiffusionMercurialWireProtocol' => 'applications/diffusion/protocol/DiffusionMercurialWireProtocol.php', + 'DiffusionMirrorDeleteController' => 'applications/diffusion/controller/DiffusionMirrorDeleteController.php', + 'DiffusionMirrorEditController' => 'applications/diffusion/controller/DiffusionMirrorEditController.php', 'DiffusionPathChange' => 'applications/diffusion/data/DiffusionPathChange.php', 'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php', 'DiffusionPathCompleteController' => 'applications/diffusion/controller/DiffusionPathCompleteController.php', @@ -1770,8 +1772,11 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryMercurialCommitChangeParserWorker.php', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryMercurialCommitMessageParserWorker.php', + 'PhabricatorRepositoryMirror' => 'applications/repository/storage/PhabricatorRepositoryMirror.php', + 'PhabricatorRepositoryMirrorQuery' => 'applications/repository/query/PhabricatorRepositoryMirrorQuery.php', 'PhabricatorRepositoryPHIDTypeArcanistProject' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeArcanistProject.php', 'PhabricatorRepositoryPHIDTypeCommit' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php', + 'PhabricatorRepositoryPHIDTypeMirror' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php', 'PhabricatorRepositoryPHIDTypeRepository' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeRepository.php', 'PhabricatorRepositoryPullEngine' => 'applications/repository/engine/PhabricatorRepositoryPullEngine.php', 'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php', @@ -2823,6 +2828,8 @@ phutil_register_library_map(array( 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionMercurialRequest' => 'DiffusionRequest', 'DiffusionMercurialResponse' => 'AphrontResponse', + 'DiffusionMirrorDeleteController' => 'DiffusionController', + 'DiffusionMirrorEditController' => 'DiffusionController', 'DiffusionPathCompleteController' => 'DiffusionController', 'DiffusionPathQueryTestCase' => 'PhabricatorTestCase', 'DiffusionPathValidateController' => 'DiffusionController', @@ -4253,8 +4260,15 @@ phutil_register_library_map(array( 'PhabricatorRepositoryManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', + 'PhabricatorRepositoryMirror' => + array( + 0 => 'PhabricatorRepositoryDAO', + 1 => 'PhabricatorPolicyInterface', + ), + 'PhabricatorRepositoryMirrorQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryPHIDTypeArcanistProject' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPHIDTypeCommit' => 'PhabricatorPHIDType', + 'PhabricatorRepositoryPHIDTypeMirror' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPHIDTypeRepository' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPullEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorDaemon', diff --git a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php index ea809aa4dc..9ca2c6ab52 100644 --- a/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php +++ b/src/applications/diffusion/application/PhabricatorApplicationDiffusion.php @@ -80,6 +80,10 @@ final class PhabricatorApplicationDiffusion extends PhabricatorApplication { 'hosting/' => 'DiffusionRepositoryEditHostingController', '(?Pserve)/' => 'DiffusionRepositoryEditHostingController', ), + 'mirror/' => array( + 'edit/(?:(?P\d+)/)?' => 'DiffusionMirrorEditController', + 'delete/(?P\d+)/' => 'DiffusionMirrorDeleteController', + ), ), // NOTE: This must come after the rule above; it just gives us a diff --git a/src/applications/diffusion/controller/DiffusionMirrorDeleteController.php b/src/applications/diffusion/controller/DiffusionMirrorDeleteController.php new file mode 100644 index 0000000000..76b824b556 --- /dev/null +++ b/src/applications/diffusion/controller/DiffusionMirrorDeleteController.php @@ -0,0 +1,47 @@ +id = $data['id']; + parent::willProcessRequest($data); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + $drequest = $this->diffusionRequest; + $repository = $drequest->getRepository(); + + $mirror = id(new PhabricatorRepositoryMirrorQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$mirror) { + return new Aphront404Response(); + } + + $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/#mirrors'); + + if ($request->isFormPost()) { + $mirror->delete(); + return id(new AphrontReloadResponse())->setURI($edit_uri); + } + + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setTitle(pht('Really delete mirror?')) + ->appendChild( + pht('Phabricator will stop pushing updates to this mirror.')) + ->addSubmitButton(pht('Delete Mirror')) + ->addCancelButton($edit_uri); + + return id(new AphrontDialogResponse()) + ->setDialog($dialog); + } + + +} diff --git a/src/applications/diffusion/controller/DiffusionMirrorEditController.php b/src/applications/diffusion/controller/DiffusionMirrorEditController.php new file mode 100644 index 0000000000..a3a6471184 --- /dev/null +++ b/src/applications/diffusion/controller/DiffusionMirrorEditController.php @@ -0,0 +1,121 @@ +id = idx($data, 'id'); + parent::willProcessRequest($data); + } + + public function processRequest() { + $request = $this->getRequest(); + $viewer = $request->getUser(); + $drequest = $this->diffusionRequest; + $repository = $drequest->getRepository(); + + if ($this->id) { + $mirror = id(new PhabricatorRepositoryMirrorQuery()) + ->setViewer($viewer) + ->withIDs(array($this->id)) + ->executeOne(); + if (!$mirror) { + return new Aphront404Response(); + } + $is_new = false; + } else { + $mirror = PhabricatorRepositoryMirror::initializeNewMirror($viewer) + ->setRepositoryPHID($repository->getPHID()) + ->attachRepository($repository); + $is_new = true; + } + + $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/#mirrors'); + + $v_remote = $mirror->getRemoteURI(); + $e_remote = true; + + $v_credentials = $mirror->getCredentialPHID(); + $e_credentials = null; + + $credentials = id(new PassphraseCredentialQuery()) + ->setViewer($viewer) + ->withIsDestroyed(false) + ->execute(); + + $errors = array(); + if ($request->isFormPost()) { + $v_remote = $request->getStr('remoteURI'); + if (strlen($v_remote)) { + $e_remote = null; + } else { + $e_remote = pht('Required'); + $errors[] = pht('You must provide a remote URI.'); + } + + $v_credentials = $request->getStr('credential'); + if ($v_credentials) { + $phids = mpull($credentials, null, 'getPHID'); + if (empty($phids[$v_credentials])) { + $e_credentials = pht('Invalid'); + $errors[] = pht( + 'You do not have permission to use those credentials.'); + } + } + + if (!$errors) { + $mirror + ->setRemoteURI($v_remote) + ->setCredentialPHID($v_credentials) + ->save(); + return id(new AphrontReloadResponse())->setURI($edit_uri); + } + } + + $form_errors = null; + if ($errors) { + $form_errors = id(new AphrontErrorView()) + ->setErrors($errors); + } + + if ($is_new) { + $title = pht('Create Mirror'); + $submit = pht('Create Mirror'); + } else { + $title = pht('Edit Mirror'); + $submit = pht('Save Changes'); + } + + $form = id(new PHUIFormLayoutView()) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel(pht('Remote URI')) + ->setName('remoteURI') + ->setValue($v_remote) + ->setError($e_remote)) + ->appendChild( + id(new PassphraseCredentialControl()) + ->setLabel(pht('Credentials')) + ->setName('credential') + ->setAllowNull(true) + ->setValue($v_credentials) + ->setError($e_credentials) + ->setOptions($credentials)); + + $dialog = id(new AphrontDialogView()) + ->setUser($viewer) + ->setTitle($title) + ->setWidth(AphrontDialogView::WIDTH_FORM) + ->appendChild($form_errors) + ->appendChild($form) + ->addSubmitButton($submit) + ->addCancelButton($edit_uri); + + return id(new AphrontDialogResponse()) + ->setDialog($dialog); + } + + +} diff --git a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php index 999ae7845f..de624a259f 100644 --- a/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php +++ b/src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php @@ -67,6 +67,7 @@ final class DiffusionRepositoryEditMainController $repository, $this->buildHostingActions($repository)); + $branches_properties = null; if ($has_branches) { $branches_properties = $this->buildBranchesProperties( @@ -114,36 +115,78 @@ final class DiffusionRepositoryEditMainController ->setTransactions($xactions) ->setMarkupEngine($engine); - $obj_box = id(new PHUIObjectBoxView()) + $boxes = array(); + + $boxes[] = id(new PHUIObjectBoxView()) ->setHeader($header) - ->addPropertyList($basic_properties) - ->addPropertyList($policy_properties) + ->addPropertyList($basic_properties); + + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Policies')) + ->addPropertyList($policy_properties); + + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Hosting')) ->addPropertyList($hosting_properties); + if ($repository->canMirror()) { + $mirror_actions = $this->buildMirrorActions($repository); + $mirror_properties = $this->buildMirrorProperties( + $repository, + $mirror_actions); + + $mirrors = id(new PhabricatorRepositoryMirrorQuery()) + ->setViewer($viewer) + ->withRepositoryPHIDs(array($repository->getPHID())) + ->execute(); + + $mirror_list = $this->buildMirrorList($repository, $mirrors); + + $boxes[] = id(new PhabricatorAnchorView())->setAnchorName('mirrors'); + + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Mirrors')) + ->addPropertyList($mirror_properties); + + $boxes[] = $mirror_list; + } + if ($remote_properties) { - $obj_box->addPropertyList($remote_properties); + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Remote')) + ->addPropertyList($remote_properties); } if ($local_properties) { - $obj_box->addPropertyList($local_properties); + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Local')) + ->addPropertyList($local_properties); } - $obj_box->addPropertyList($encoding_properties); + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Text Encoding')) + ->addPropertyList($encoding_properties); if ($branches_properties) { - $obj_box->addPropertyList($branches_properties); + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Branches')) + ->addPropertyList($branches_properties); } if ($subversion_properties) { - $obj_box->addPropertyList($subversion_properties); + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Subversion')) + ->addPropertyList($subversion_properties); } - $obj_box->addPropertyList($actions_properties); + $boxes[] = id(new PHUIObjectBoxView()) + ->setHeaderText(pht('Actions')) + ->addPropertyList($actions_properties); return $this->buildApplicationPage( array( $crumbs, - $obj_box, + $boxes, $xaction_view, ), array( @@ -253,8 +296,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($viewer) - ->setActionList($actions) - ->addSectionHeader(pht('Text Encoding')); + ->setActionList($actions); $encoding = $repository->getDetail('encoding'); if (!$encoding) { @@ -291,8 +333,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($viewer) - ->setActionList($actions) - ->addSectionHeader(pht('Policies')); + ->setActionList($actions); $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( $viewer, @@ -339,8 +380,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($viewer) - ->setActionList($actions) - ->addSectionHeader(pht('Branches')); + ->setActionList($actions); $default_branch = nonempty( $repository->getHumanReadableDetail('default-branch'), @@ -390,8 +430,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($viewer) - ->setActionList($actions) - ->addSectionHeader(pht('Subversion')); + ->setActionList($actions); $svn_uuid = nonempty( $repository->getUUID(), @@ -431,8 +470,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($viewer) - ->setActionList($actions) - ->addSectionHeader(pht('Actions')); + ->setActionList($actions); $notify = $repository->getDetail('herald-disabled') ? pht('Off') @@ -474,8 +512,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($viewer) - ->setActionList($actions) - ->addSectionHeader(pht('Remote')); + ->setActionList($actions); $view->addProperty( pht('Remote URI'), @@ -517,8 +554,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($viewer) - ->setActionList($actions) - ->addSectionHeader(pht('Local')); + ->setActionList($actions); $view->addProperty( pht('Local Path'), @@ -552,8 +588,7 @@ final class DiffusionRepositoryEditMainController $view = id(new PHUIPropertyListView()) ->setUser($user) - ->setActionList($actions) - ->addSectionHeader(pht('Hosting')); + ->setActionList($actions); $hosting = $repository->isHosted() ? pht('Hosted on Phabricator') @@ -903,4 +938,86 @@ final class DiffusionRepositoryEditMainController return $view; } + private function buildMirrorActions( + PhabricatorRepository $repository) { + + $viewer = $this->getRequest()->getUser(); + + $mirror_actions = id(new PhabricatorActionListView()) + ->setObjectURI($this->getRequest()->getRequestURI()) + ->setUser($viewer); + + $new_mirror_uri = $this->getRepositoryControllerURI( + $repository, + 'mirror/edit/'); + + $mirror_actions->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Add Mirror')) + ->setIcon('new') + ->setHref($new_mirror_uri) + ->setWorkflow(true)); + + return $mirror_actions; + } + + private function buildMirrorProperties( + PhabricatorRepository $repository, + PhabricatorActionListView $actions) { + + $viewer = $this->getRequest()->getUser(); + + $mirror_properties = id(new PHUIPropertyListView()) + ->setUser($viewer) + ->setActionList($actions); + + $mirror_properties->addProperty( + '', + phutil_tag( + 'em', + array(), + pht('Automatically push changes into other remotes.'))); + + return $mirror_properties; + } + + private function buildMirrorList( + PhabricatorRepository $repository, + array $mirrors) { + assert_instances_of($mirrors, 'PhabricatorRepositoryMirror'); + + $mirror_list = id(new PHUIObjectItemListView()) + ->setNoDataString(pht('This repository has no configured mirrors.')); + + foreach ($mirrors as $mirror) { + $item = id(new PHUIObjectItemView()) + ->setHeader($mirror->getRemoteURI()); + + $edit_uri = $this->getRepositoryControllerURI( + $repository, + 'mirror/edit/'.$mirror->getID().'/'); + + $delete_uri = $this->getRepositoryControllerURI( + $repository, + 'mirror/delete/'.$mirror->getID().'/'); + + $item->addAction( + id(new PHUIListItemView()) + ->setIcon('edit') + ->setHref($edit_uri) + ->setWorkflow(true)); + + $item->addAction( + id(new PHUIListItemView()) + ->setIcon('delete') + ->setHref($delete_uri) + ->setWorkflow(true)); + + $mirror_list->addItem($item); + } + + return $mirror_list; + } + + } diff --git a/src/applications/passphrase/view/PassphraseCredentialControl.php b/src/applications/passphrase/view/PassphraseCredentialControl.php index 8ba1659481..87f315ca59 100644 --- a/src/applications/passphrase/view/PassphraseCredentialControl.php +++ b/src/applications/passphrase/view/PassphraseCredentialControl.php @@ -68,15 +68,19 @@ final class PassphraseCredentialControl extends AphrontFormControl { 'sigil' => 'passphrase-credential-select', )); - $button = javelin_tag( - 'a', - array( - 'href' => '#', - 'class' => 'button grey', - 'sigil' => 'passphrase-credential-add', - 'mustcapture' => true, - ), - pht('Add Credential')); + if ($this->credentialType) { + $button = javelin_tag( + 'a', + array( + 'href' => '#', + 'class' => 'button grey', + 'sigil' => 'passphrase-credential-add', + 'mustcapture' => true, + ), + pht('Add Credential')); + } else { + $button = null; + } return javelin_tag( 'div', diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php b/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php new file mode 100644 index 0000000000..72c6570ca4 --- /dev/null +++ b/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php @@ -0,0 +1,47 @@ +withPHIDs($phids); + } + + public function loadHandles( + PhabricatorHandleQuery $query, + array $handles, + array $objects) { + + foreach ($handles as $phid => $handle) { + $mirror = $objects[$phid]; + + $handle->setName( + pht('Mirror %d %s', $mirror->getID(), $mirror->getRemoteURI())); + $handle->setURI("/diffusion/mirror/".$mirror->getID()."/"); + } + } + + public function canLoadNamedObject($name) { + return false; + } + + +} diff --git a/src/applications/repository/query/PhabricatorRepositoryMirrorQuery.php b/src/applications/repository/query/PhabricatorRepositoryMirrorQuery.php new file mode 100644 index 0000000000..2f8f7fc96e --- /dev/null +++ b/src/applications/repository/query/PhabricatorRepositoryMirrorQuery.php @@ -0,0 +1,101 @@ +ids = $ids; + return $this; + } + + public function withPHIDs(array $phids) { + $this->phids = $phids; + return $this; + } + + public function withRepositoryPHIDs(array $repository_phids) { + $this->repositoryPHIDs = $repository_phids; + return $this; + } + + protected function loadPage() { + $table = new PhabricatorRepositoryMirror(); + $conn_r = $table->establishConnection('r'); + + $data = queryfx_all( + $conn_r, + 'SELECT * FROM %T %Q %Q %Q', + $table->getTableName(), + $this->buildWhereClause($conn_r), + $this->buildOrderClause($conn_r), + $this->buildLimitClause($conn_r)); + + return $table->loadAllFromArray($data); + } + + public function willFilterPage(array $mirrors) { + assert_instances_of($mirrors, 'PhabricatorRepositoryMirror'); + + $repository_phids = mpull($mirrors, 'getRepositoryPHID'); + if ($repository_phids) { + $repositories = id(new PhabricatorRepositoryQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs($repository_phids) + ->execute(); + $repositories = mpull($repositories, null, 'getPHID'); + } else { + $repositories = array(); + } + + foreach ($mirrors as $key => $mirror) { + $phid = $mirror->getRepositoryPHID(); + if (empty($repositories[$phid])) { + unset($mirrors[$key]); + continue; + } + $mirror->attachRepository($repositories[$phid]); + } + + return $mirrors; + } + + + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { + $where = array(); + + if ($this->ids) { + $where[] = qsprintf( + $conn_r, + 'id IN (%Ld)', + $this->ids); + } + + if ($this->phids) { + $where[] = qsprintf( + $conn_r, + 'phid IN (%Ls)', + $this->phids); + } + + if ($this->repositoryPHIDs) { + $where[] = qsprintf( + $conn_r, + 'repositoryPHID IN (%Ls)', + $this->repositoryPHIDs); + } + + $where[] = $this->buildPagingClause($conn_r); + + return $this->formatWhereClause($where); + } + + + public function getQueryApplicationClass() { + return 'PhabricatorApplicationDiffusion'; + } + +} diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index af00bb58e8..3bbaa9901b 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -740,6 +740,12 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO $commit->delete(); } + $mirrors = id(new PhabricatorRepositoryMirror()) + ->loadAllWhere('repositoryPHID = %s', $this->getPHID()); + foreach ($mirrors as $mirror) { + $mirror->delete(); + } + $conn_w = $this->establishConnection('w'); queryfx( @@ -894,6 +900,17 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO return Filesystem::isDescendant($this->getLocalPath(), $default_path); } + public function canMirror() { + if (!$this->isHosted()) { + return false; + } + + if ($this->isGit()) { + return true; + } + + return false; + } public function writeStatusMessage( $status_type, diff --git a/src/applications/repository/storage/PhabricatorRepositoryMirror.php b/src/applications/repository/storage/PhabricatorRepositoryMirror.php new file mode 100644 index 0000000000..a4205d4dc8 --- /dev/null +++ b/src/applications/repository/storage/PhabricatorRepositoryMirror.php @@ -0,0 +1,60 @@ +setRemoteURI(''); + } + + public function getConfiguration() { + return array( + self::CONFIG_AUX_PHID => true, + ) + parent::getConfiguration(); + } + + public function generatePHID() { + return PhabricatorPHID::generateNewPHID( + PhabricatorRepositoryPHIDTypeMirror::TYPECONST); + } + + public function attachRepository(PhabricatorRepository $repository) { + $this->repository = $repository; + return $this; + } + + public function getRepository() { + return $this->assertAttached($this->repository); + } + + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ); + } + + public function getPolicy($capability) { + return $this->getRepository()->getPolicy($capability); + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return $this->getRepository()->hasAutomaticCapability($capability, $viewer); + } + + public function describeAutomaticCapability($capability) { + return null; + } + +} diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php index 95ffc58695..71daeb025a 100644 --- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1784,6 +1784,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList { 'type' => 'php', 'name' => $this->getPatchPath('20131121.repocredentials.2.mig.php'), ), + '20131122.repomirror.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('20131122.repomirror.sql'), + ), ); } }