@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

+584 -35
+13
resources/sql/patches/20131122.repomirror.sql
··· 1 + CREATE TABLE {$NAMESPACE}_repository.repository_mirror ( 2 + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, 3 + phid VARCHAR(64) NOT NULL COLLATE utf8_bin, 4 + repositoryPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, 5 + remoteURI VARCHAR(255) NOT NULL COLLATE utf8_bin, 6 + credentialPHID VARCHAR(64) COLLATE utf8_bin, 7 + dateCreated INT UNSIGNED NOT NULL, 8 + dateModified INT UNSIGNED NOT NULL, 9 + 10 + UNIQUE KEY `key_phid` (phid), 11 + KEY `key_repository` (repositoryPHID) 12 + 13 + ) ENGINE=InnoDB, COLLATE utf8_general_ci;
+14
src/__phutil_library_map__.php
··· 510 510 'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php', 511 511 'DiffusionMercurialResponse' => 'applications/diffusion/response/DiffusionMercurialResponse.php', 512 512 'DiffusionMercurialWireProtocol' => 'applications/diffusion/protocol/DiffusionMercurialWireProtocol.php', 513 + 'DiffusionMirrorDeleteController' => 'applications/diffusion/controller/DiffusionMirrorDeleteController.php', 514 + 'DiffusionMirrorEditController' => 'applications/diffusion/controller/DiffusionMirrorEditController.php', 513 515 'DiffusionPathChange' => 'applications/diffusion/data/DiffusionPathChange.php', 514 516 'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php', 515 517 'DiffusionPathCompleteController' => 'applications/diffusion/controller/DiffusionPathCompleteController.php', ··· 1770 1772 'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php', 1771 1773 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryMercurialCommitChangeParserWorker.php', 1772 1774 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryMercurialCommitMessageParserWorker.php', 1775 + 'PhabricatorRepositoryMirror' => 'applications/repository/storage/PhabricatorRepositoryMirror.php', 1776 + 'PhabricatorRepositoryMirrorQuery' => 'applications/repository/query/PhabricatorRepositoryMirrorQuery.php', 1773 1777 'PhabricatorRepositoryPHIDTypeArcanistProject' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeArcanistProject.php', 1774 1778 'PhabricatorRepositoryPHIDTypeCommit' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php', 1779 + 'PhabricatorRepositoryPHIDTypeMirror' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php', 1775 1780 'PhabricatorRepositoryPHIDTypeRepository' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeRepository.php', 1776 1781 'PhabricatorRepositoryPullEngine' => 'applications/repository/engine/PhabricatorRepositoryPullEngine.php', 1777 1782 'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php', ··· 2823 2828 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', 2824 2829 'DiffusionMercurialRequest' => 'DiffusionRequest', 2825 2830 'DiffusionMercurialResponse' => 'AphrontResponse', 2831 + 'DiffusionMirrorDeleteController' => 'DiffusionController', 2832 + 'DiffusionMirrorEditController' => 'DiffusionController', 2826 2833 'DiffusionPathCompleteController' => 'DiffusionController', 2827 2834 'DiffusionPathQueryTestCase' => 'PhabricatorTestCase', 2828 2835 'DiffusionPathValidateController' => 'DiffusionController', ··· 4253 4260 'PhabricatorRepositoryManagementWorkflow' => 'PhutilArgumentWorkflow', 4254 4261 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 4255 4262 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 4263 + 'PhabricatorRepositoryMirror' => 4264 + array( 4265 + 0 => 'PhabricatorRepositoryDAO', 4266 + 1 => 'PhabricatorPolicyInterface', 4267 + ), 4268 + 'PhabricatorRepositoryMirrorQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 4256 4269 'PhabricatorRepositoryPHIDTypeArcanistProject' => 'PhabricatorPHIDType', 4257 4270 'PhabricatorRepositoryPHIDTypeCommit' => 'PhabricatorPHIDType', 4271 + 'PhabricatorRepositoryPHIDTypeMirror' => 'PhabricatorPHIDType', 4258 4272 'PhabricatorRepositoryPHIDTypeRepository' => 'PhabricatorPHIDType', 4259 4273 'PhabricatorRepositoryPullEngine' => 'PhabricatorRepositoryEngine', 4260 4274 'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorDaemon',
+4
src/applications/diffusion/application/PhabricatorApplicationDiffusion.php
··· 80 80 'hosting/' => 'DiffusionRepositoryEditHostingController', 81 81 '(?P<serve>serve)/' => 'DiffusionRepositoryEditHostingController', 82 82 ), 83 + 'mirror/' => array( 84 + 'edit/(?:(?P<id>\d+)/)?' => 'DiffusionMirrorEditController', 85 + 'delete/(?P<id>\d+)/' => 'DiffusionMirrorDeleteController', 86 + ), 83 87 ), 84 88 85 89 // NOTE: This must come after the rule above; it just gives us a
+47
src/applications/diffusion/controller/DiffusionMirrorDeleteController.php
··· 1 + <?php 2 + 3 + final class DiffusionMirrorDeleteController 4 + extends DiffusionController { 5 + 6 + private $id; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->id = $data['id']; 10 + parent::willProcessRequest($data); 11 + } 12 + 13 + public function processRequest() { 14 + $request = $this->getRequest(); 15 + $viewer = $request->getUser(); 16 + $drequest = $this->diffusionRequest; 17 + $repository = $drequest->getRepository(); 18 + 19 + $mirror = id(new PhabricatorRepositoryMirrorQuery()) 20 + ->setViewer($viewer) 21 + ->withIDs(array($this->id)) 22 + ->executeOne(); 23 + if (!$mirror) { 24 + return new Aphront404Response(); 25 + } 26 + 27 + $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/#mirrors'); 28 + 29 + if ($request->isFormPost()) { 30 + $mirror->delete(); 31 + return id(new AphrontReloadResponse())->setURI($edit_uri); 32 + } 33 + 34 + $dialog = id(new AphrontDialogView()) 35 + ->setUser($viewer) 36 + ->setTitle(pht('Really delete mirror?')) 37 + ->appendChild( 38 + pht('Phabricator will stop pushing updates to this mirror.')) 39 + ->addSubmitButton(pht('Delete Mirror')) 40 + ->addCancelButton($edit_uri); 41 + 42 + return id(new AphrontDialogResponse()) 43 + ->setDialog($dialog); 44 + } 45 + 46 + 47 + }
+121
src/applications/diffusion/controller/DiffusionMirrorEditController.php
··· 1 + <?php 2 + 3 + final class DiffusionMirrorEditController 4 + extends DiffusionController { 5 + 6 + private $id; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->id = idx($data, 'id'); 10 + parent::willProcessRequest($data); 11 + } 12 + 13 + public function processRequest() { 14 + $request = $this->getRequest(); 15 + $viewer = $request->getUser(); 16 + $drequest = $this->diffusionRequest; 17 + $repository = $drequest->getRepository(); 18 + 19 + if ($this->id) { 20 + $mirror = id(new PhabricatorRepositoryMirrorQuery()) 21 + ->setViewer($viewer) 22 + ->withIDs(array($this->id)) 23 + ->executeOne(); 24 + if (!$mirror) { 25 + return new Aphront404Response(); 26 + } 27 + $is_new = false; 28 + } else { 29 + $mirror = PhabricatorRepositoryMirror::initializeNewMirror($viewer) 30 + ->setRepositoryPHID($repository->getPHID()) 31 + ->attachRepository($repository); 32 + $is_new = true; 33 + } 34 + 35 + $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/#mirrors'); 36 + 37 + $v_remote = $mirror->getRemoteURI(); 38 + $e_remote = true; 39 + 40 + $v_credentials = $mirror->getCredentialPHID(); 41 + $e_credentials = null; 42 + 43 + $credentials = id(new PassphraseCredentialQuery()) 44 + ->setViewer($viewer) 45 + ->withIsDestroyed(false) 46 + ->execute(); 47 + 48 + $errors = array(); 49 + if ($request->isFormPost()) { 50 + $v_remote = $request->getStr('remoteURI'); 51 + if (strlen($v_remote)) { 52 + $e_remote = null; 53 + } else { 54 + $e_remote = pht('Required'); 55 + $errors[] = pht('You must provide a remote URI.'); 56 + } 57 + 58 + $v_credentials = $request->getStr('credential'); 59 + if ($v_credentials) { 60 + $phids = mpull($credentials, null, 'getPHID'); 61 + if (empty($phids[$v_credentials])) { 62 + $e_credentials = pht('Invalid'); 63 + $errors[] = pht( 64 + 'You do not have permission to use those credentials.'); 65 + } 66 + } 67 + 68 + if (!$errors) { 69 + $mirror 70 + ->setRemoteURI($v_remote) 71 + ->setCredentialPHID($v_credentials) 72 + ->save(); 73 + return id(new AphrontReloadResponse())->setURI($edit_uri); 74 + } 75 + } 76 + 77 + $form_errors = null; 78 + if ($errors) { 79 + $form_errors = id(new AphrontErrorView()) 80 + ->setErrors($errors); 81 + } 82 + 83 + if ($is_new) { 84 + $title = pht('Create Mirror'); 85 + $submit = pht('Create Mirror'); 86 + } else { 87 + $title = pht('Edit Mirror'); 88 + $submit = pht('Save Changes'); 89 + } 90 + 91 + $form = id(new PHUIFormLayoutView()) 92 + ->appendChild( 93 + id(new AphrontFormTextControl()) 94 + ->setLabel(pht('Remote URI')) 95 + ->setName('remoteURI') 96 + ->setValue($v_remote) 97 + ->setError($e_remote)) 98 + ->appendChild( 99 + id(new PassphraseCredentialControl()) 100 + ->setLabel(pht('Credentials')) 101 + ->setName('credential') 102 + ->setAllowNull(true) 103 + ->setValue($v_credentials) 104 + ->setError($e_credentials) 105 + ->setOptions($credentials)); 106 + 107 + $dialog = id(new AphrontDialogView()) 108 + ->setUser($viewer) 109 + ->setTitle($title) 110 + ->setWidth(AphrontDialogView::WIDTH_FORM) 111 + ->appendChild($form_errors) 112 + ->appendChild($form) 113 + ->addSubmitButton($submit) 114 + ->addCancelButton($edit_uri); 115 + 116 + return id(new AphrontDialogResponse()) 117 + ->setDialog($dialog); 118 + } 119 + 120 + 121 + }
+143 -26
src/applications/diffusion/controller/DiffusionRepositoryEditMainController.php
··· 67 67 $repository, 68 68 $this->buildHostingActions($repository)); 69 69 70 + 70 71 $branches_properties = null; 71 72 if ($has_branches) { 72 73 $branches_properties = $this->buildBranchesProperties( ··· 114 115 ->setTransactions($xactions) 115 116 ->setMarkupEngine($engine); 116 117 117 - $obj_box = id(new PHUIObjectBoxView()) 118 + $boxes = array(); 119 + 120 + $boxes[] = id(new PHUIObjectBoxView()) 118 121 ->setHeader($header) 119 - ->addPropertyList($basic_properties) 120 - ->addPropertyList($policy_properties) 122 + ->addPropertyList($basic_properties); 123 + 124 + $boxes[] = id(new PHUIObjectBoxView()) 125 + ->setHeaderText(pht('Policies')) 126 + ->addPropertyList($policy_properties); 127 + 128 + $boxes[] = id(new PHUIObjectBoxView()) 129 + ->setHeaderText(pht('Hosting')) 121 130 ->addPropertyList($hosting_properties); 122 131 132 + if ($repository->canMirror()) { 133 + $mirror_actions = $this->buildMirrorActions($repository); 134 + $mirror_properties = $this->buildMirrorProperties( 135 + $repository, 136 + $mirror_actions); 137 + 138 + $mirrors = id(new PhabricatorRepositoryMirrorQuery()) 139 + ->setViewer($viewer) 140 + ->withRepositoryPHIDs(array($repository->getPHID())) 141 + ->execute(); 142 + 143 + $mirror_list = $this->buildMirrorList($repository, $mirrors); 144 + 145 + $boxes[] = id(new PhabricatorAnchorView())->setAnchorName('mirrors'); 146 + 147 + $boxes[] = id(new PHUIObjectBoxView()) 148 + ->setHeaderText(pht('Mirrors')) 149 + ->addPropertyList($mirror_properties); 150 + 151 + $boxes[] = $mirror_list; 152 + } 153 + 123 154 if ($remote_properties) { 124 - $obj_box->addPropertyList($remote_properties); 155 + $boxes[] = id(new PHUIObjectBoxView()) 156 + ->setHeaderText(pht('Remote')) 157 + ->addPropertyList($remote_properties); 125 158 } 126 159 127 160 if ($local_properties) { 128 - $obj_box->addPropertyList($local_properties); 161 + $boxes[] = id(new PHUIObjectBoxView()) 162 + ->setHeaderText(pht('Local')) 163 + ->addPropertyList($local_properties); 129 164 } 130 165 131 - $obj_box->addPropertyList($encoding_properties); 166 + $boxes[] = id(new PHUIObjectBoxView()) 167 + ->setHeaderText(pht('Text Encoding')) 168 + ->addPropertyList($encoding_properties); 132 169 133 170 if ($branches_properties) { 134 - $obj_box->addPropertyList($branches_properties); 171 + $boxes[] = id(new PHUIObjectBoxView()) 172 + ->setHeaderText(pht('Branches')) 173 + ->addPropertyList($branches_properties); 135 174 } 136 175 137 176 if ($subversion_properties) { 138 - $obj_box->addPropertyList($subversion_properties); 177 + $boxes[] = id(new PHUIObjectBoxView()) 178 + ->setHeaderText(pht('Subversion')) 179 + ->addPropertyList($subversion_properties); 139 180 } 140 181 141 - $obj_box->addPropertyList($actions_properties); 182 + $boxes[] = id(new PHUIObjectBoxView()) 183 + ->setHeaderText(pht('Actions')) 184 + ->addPropertyList($actions_properties); 142 185 143 186 return $this->buildApplicationPage( 144 187 array( 145 188 $crumbs, 146 - $obj_box, 189 + $boxes, 147 190 $xaction_view, 148 191 ), 149 192 array( ··· 253 296 254 297 $view = id(new PHUIPropertyListView()) 255 298 ->setUser($viewer) 256 - ->setActionList($actions) 257 - ->addSectionHeader(pht('Text Encoding')); 299 + ->setActionList($actions); 258 300 259 301 $encoding = $repository->getDetail('encoding'); 260 302 if (!$encoding) { ··· 291 333 292 334 $view = id(new PHUIPropertyListView()) 293 335 ->setUser($viewer) 294 - ->setActionList($actions) 295 - ->addSectionHeader(pht('Policies')); 336 + ->setActionList($actions); 296 337 297 338 $descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions( 298 339 $viewer, ··· 339 380 340 381 $view = id(new PHUIPropertyListView()) 341 382 ->setUser($viewer) 342 - ->setActionList($actions) 343 - ->addSectionHeader(pht('Branches')); 383 + ->setActionList($actions); 344 384 345 385 $default_branch = nonempty( 346 386 $repository->getHumanReadableDetail('default-branch'), ··· 390 430 391 431 $view = id(new PHUIPropertyListView()) 392 432 ->setUser($viewer) 393 - ->setActionList($actions) 394 - ->addSectionHeader(pht('Subversion')); 433 + ->setActionList($actions); 395 434 396 435 $svn_uuid = nonempty( 397 436 $repository->getUUID(), ··· 431 470 432 471 $view = id(new PHUIPropertyListView()) 433 472 ->setUser($viewer) 434 - ->setActionList($actions) 435 - ->addSectionHeader(pht('Actions')); 473 + ->setActionList($actions); 436 474 437 475 $notify = $repository->getDetail('herald-disabled') 438 476 ? pht('Off') ··· 474 512 475 513 $view = id(new PHUIPropertyListView()) 476 514 ->setUser($viewer) 477 - ->setActionList($actions) 478 - ->addSectionHeader(pht('Remote')); 515 + ->setActionList($actions); 479 516 480 517 $view->addProperty( 481 518 pht('Remote URI'), ··· 517 554 518 555 $view = id(new PHUIPropertyListView()) 519 556 ->setUser($viewer) 520 - ->setActionList($actions) 521 - ->addSectionHeader(pht('Local')); 557 + ->setActionList($actions); 522 558 523 559 $view->addProperty( 524 560 pht('Local Path'), ··· 552 588 553 589 $view = id(new PHUIPropertyListView()) 554 590 ->setUser($user) 555 - ->setActionList($actions) 556 - ->addSectionHeader(pht('Hosting')); 591 + ->setActionList($actions); 557 592 558 593 $hosting = $repository->isHosted() 559 594 ? pht('Hosted on Phabricator') ··· 902 937 903 938 return $view; 904 939 } 940 + 941 + private function buildMirrorActions( 942 + PhabricatorRepository $repository) { 943 + 944 + $viewer = $this->getRequest()->getUser(); 945 + 946 + $mirror_actions = id(new PhabricatorActionListView()) 947 + ->setObjectURI($this->getRequest()->getRequestURI()) 948 + ->setUser($viewer); 949 + 950 + $new_mirror_uri = $this->getRepositoryControllerURI( 951 + $repository, 952 + 'mirror/edit/'); 953 + 954 + $mirror_actions->addAction( 955 + id(new PhabricatorActionView()) 956 + ->setName(pht('Add Mirror')) 957 + ->setIcon('new') 958 + ->setHref($new_mirror_uri) 959 + ->setWorkflow(true)); 960 + 961 + return $mirror_actions; 962 + } 963 + 964 + private function buildMirrorProperties( 965 + PhabricatorRepository $repository, 966 + PhabricatorActionListView $actions) { 967 + 968 + $viewer = $this->getRequest()->getUser(); 969 + 970 + $mirror_properties = id(new PHUIPropertyListView()) 971 + ->setUser($viewer) 972 + ->setActionList($actions); 973 + 974 + $mirror_properties->addProperty( 975 + '', 976 + phutil_tag( 977 + 'em', 978 + array(), 979 + pht('Automatically push changes into other remotes.'))); 980 + 981 + return $mirror_properties; 982 + } 983 + 984 + private function buildMirrorList( 985 + PhabricatorRepository $repository, 986 + array $mirrors) { 987 + assert_instances_of($mirrors, 'PhabricatorRepositoryMirror'); 988 + 989 + $mirror_list = id(new PHUIObjectItemListView()) 990 + ->setNoDataString(pht('This repository has no configured mirrors.')); 991 + 992 + foreach ($mirrors as $mirror) { 993 + $item = id(new PHUIObjectItemView()) 994 + ->setHeader($mirror->getRemoteURI()); 995 + 996 + $edit_uri = $this->getRepositoryControllerURI( 997 + $repository, 998 + 'mirror/edit/'.$mirror->getID().'/'); 999 + 1000 + $delete_uri = $this->getRepositoryControllerURI( 1001 + $repository, 1002 + 'mirror/delete/'.$mirror->getID().'/'); 1003 + 1004 + $item->addAction( 1005 + id(new PHUIListItemView()) 1006 + ->setIcon('edit') 1007 + ->setHref($edit_uri) 1008 + ->setWorkflow(true)); 1009 + 1010 + $item->addAction( 1011 + id(new PHUIListItemView()) 1012 + ->setIcon('delete') 1013 + ->setHref($delete_uri) 1014 + ->setWorkflow(true)); 1015 + 1016 + $mirror_list->addItem($item); 1017 + } 1018 + 1019 + return $mirror_list; 1020 + } 1021 + 905 1022 906 1023 }
+13 -9
src/applications/passphrase/view/PassphraseCredentialControl.php
··· 68 68 'sigil' => 'passphrase-credential-select', 69 69 )); 70 70 71 - $button = javelin_tag( 72 - 'a', 73 - array( 74 - 'href' => '#', 75 - 'class' => 'button grey', 76 - 'sigil' => 'passphrase-credential-add', 77 - 'mustcapture' => true, 78 - ), 79 - pht('Add Credential')); 71 + if ($this->credentialType) { 72 + $button = javelin_tag( 73 + 'a', 74 + array( 75 + 'href' => '#', 76 + 'class' => 'button grey', 77 + 'sigil' => 'passphrase-credential-add', 78 + 'mustcapture' => true, 79 + ), 80 + pht('Add Credential')); 81 + } else { 82 + $button = null; 83 + } 80 84 81 85 return javelin_tag( 82 86 'div',
+47
src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryPHIDTypeMirror 4 + extends PhabricatorPHIDType { 5 + 6 + const TYPECONST = 'RMIR'; 7 + 8 + public function getTypeConstant() { 9 + return self::TYPECONST; 10 + } 11 + 12 + public function getTypeName() { 13 + return pht('Repository Mirror'); 14 + } 15 + 16 + public function newObject() { 17 + return new PhabricatorRepositoryMirror(); 18 + } 19 + 20 + protected function buildQueryForObjects( 21 + PhabricatorObjectQuery $query, 22 + array $phids) { 23 + 24 + return id(new PhabricatorRepositoryMirrorQuery()) 25 + ->withPHIDs($phids); 26 + } 27 + 28 + public function loadHandles( 29 + PhabricatorHandleQuery $query, 30 + array $handles, 31 + array $objects) { 32 + 33 + foreach ($handles as $phid => $handle) { 34 + $mirror = $objects[$phid]; 35 + 36 + $handle->setName( 37 + pht('Mirror %d %s', $mirror->getID(), $mirror->getRemoteURI())); 38 + $handle->setURI("/diffusion/mirror/".$mirror->getID()."/"); 39 + } 40 + } 41 + 42 + public function canLoadNamedObject($name) { 43 + return false; 44 + } 45 + 46 + 47 + }
+101
src/applications/repository/query/PhabricatorRepositoryMirrorQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryMirrorQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $ids; 7 + private $phids; 8 + private $repositoryPHIDs; 9 + 10 + public function withIDs(array $ids) { 11 + $this->ids = $ids; 12 + return $this; 13 + } 14 + 15 + public function withPHIDs(array $phids) { 16 + $this->phids = $phids; 17 + return $this; 18 + } 19 + 20 + public function withRepositoryPHIDs(array $repository_phids) { 21 + $this->repositoryPHIDs = $repository_phids; 22 + return $this; 23 + } 24 + 25 + protected function loadPage() { 26 + $table = new PhabricatorRepositoryMirror(); 27 + $conn_r = $table->establishConnection('r'); 28 + 29 + $data = queryfx_all( 30 + $conn_r, 31 + 'SELECT * FROM %T %Q %Q %Q', 32 + $table->getTableName(), 33 + $this->buildWhereClause($conn_r), 34 + $this->buildOrderClause($conn_r), 35 + $this->buildLimitClause($conn_r)); 36 + 37 + return $table->loadAllFromArray($data); 38 + } 39 + 40 + public function willFilterPage(array $mirrors) { 41 + assert_instances_of($mirrors, 'PhabricatorRepositoryMirror'); 42 + 43 + $repository_phids = mpull($mirrors, 'getRepositoryPHID'); 44 + if ($repository_phids) { 45 + $repositories = id(new PhabricatorRepositoryQuery()) 46 + ->setViewer($this->getViewer()) 47 + ->withPHIDs($repository_phids) 48 + ->execute(); 49 + $repositories = mpull($repositories, null, 'getPHID'); 50 + } else { 51 + $repositories = array(); 52 + } 53 + 54 + foreach ($mirrors as $key => $mirror) { 55 + $phid = $mirror->getRepositoryPHID(); 56 + if (empty($repositories[$phid])) { 57 + unset($mirrors[$key]); 58 + continue; 59 + } 60 + $mirror->attachRepository($repositories[$phid]); 61 + } 62 + 63 + return $mirrors; 64 + } 65 + 66 + 67 + private function buildWhereClause(AphrontDatabaseConnection $conn_r) { 68 + $where = array(); 69 + 70 + if ($this->ids) { 71 + $where[] = qsprintf( 72 + $conn_r, 73 + 'id IN (%Ld)', 74 + $this->ids); 75 + } 76 + 77 + if ($this->phids) { 78 + $where[] = qsprintf( 79 + $conn_r, 80 + 'phid IN (%Ls)', 81 + $this->phids); 82 + } 83 + 84 + if ($this->repositoryPHIDs) { 85 + $where[] = qsprintf( 86 + $conn_r, 87 + 'repositoryPHID IN (%Ls)', 88 + $this->repositoryPHIDs); 89 + } 90 + 91 + $where[] = $this->buildPagingClause($conn_r); 92 + 93 + return $this->formatWhereClause($where); 94 + } 95 + 96 + 97 + public function getQueryApplicationClass() { 98 + return 'PhabricatorApplicationDiffusion'; 99 + } 100 + 101 + }
+17
src/applications/repository/storage/PhabricatorRepository.php
··· 740 740 $commit->delete(); 741 741 } 742 742 743 + $mirrors = id(new PhabricatorRepositoryMirror()) 744 + ->loadAllWhere('repositoryPHID = %s', $this->getPHID()); 745 + foreach ($mirrors as $mirror) { 746 + $mirror->delete(); 747 + } 748 + 743 749 $conn_w = $this->establishConnection('w'); 744 750 745 751 queryfx( ··· 894 900 return Filesystem::isDescendant($this->getLocalPath(), $default_path); 895 901 } 896 902 903 + public function canMirror() { 904 + if (!$this->isHosted()) { 905 + return false; 906 + } 907 + 908 + if ($this->isGit()) { 909 + return true; 910 + } 911 + 912 + return false; 913 + } 897 914 898 915 public function writeStatusMessage( 899 916 $status_type,
+60
src/applications/repository/storage/PhabricatorRepositoryMirror.php
··· 1 + <?php 2 + 3 + final class PhabricatorRepositoryMirror extends PhabricatorRepositoryDAO 4 + implements PhabricatorPolicyInterface { 5 + 6 + protected $repositoryPHID; 7 + protected $remoteURI; 8 + protected $credentialPHID; 9 + 10 + private $repository = self::ATTACHABLE; 11 + 12 + public static function initializeNewMirror(PhabricatorUser $actor) { 13 + return id(new PhabricatorRepositoryMirror()) 14 + ->setRemoteURI(''); 15 + } 16 + 17 + public function getConfiguration() { 18 + return array( 19 + self::CONFIG_AUX_PHID => true, 20 + ) + parent::getConfiguration(); 21 + } 22 + 23 + public function generatePHID() { 24 + return PhabricatorPHID::generateNewPHID( 25 + PhabricatorRepositoryPHIDTypeMirror::TYPECONST); 26 + } 27 + 28 + public function attachRepository(PhabricatorRepository $repository) { 29 + $this->repository = $repository; 30 + return $this; 31 + } 32 + 33 + public function getRepository() { 34 + return $this->assertAttached($this->repository); 35 + } 36 + 37 + 38 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 39 + 40 + 41 + public function getCapabilities() { 42 + return array( 43 + PhabricatorPolicyCapability::CAN_VIEW, 44 + PhabricatorPolicyCapability::CAN_EDIT, 45 + ); 46 + } 47 + 48 + public function getPolicy($capability) { 49 + return $this->getRepository()->getPolicy($capability); 50 + } 51 + 52 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 53 + return $this->getRepository()->hasAutomaticCapability($capability, $viewer); 54 + } 55 + 56 + public function describeAutomaticCapability($capability) { 57 + return null; 58 + } 59 + 60 + }
+4
src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php
··· 1784 1784 'type' => 'php', 1785 1785 'name' => $this->getPatchPath('20131121.repocredentials.2.mig.php'), 1786 1786 ), 1787 + '20131122.repomirror.sql' => array( 1788 + 'type' => 'sql', 1789 + 'name' => $this->getPatchPath('20131122.repomirror.sql'), 1790 + ), 1787 1791 ); 1788 1792 } 1789 1793 }