2013-10-26 00:58:58 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class DiffusionRepositoryEditMainController
|
|
|
|
extends DiffusionRepositoryEditController {
|
|
|
|
|
2015-01-09 22:29:08 +01:00
|
|
|
protected function processDiffusionRequest(AphrontRequest $request) {
|
2013-10-26 00:58:58 +02:00
|
|
|
$viewer = $request->getUser();
|
|
|
|
$drequest = $this->diffusionRequest;
|
|
|
|
$repository = $drequest->getRepository();
|
|
|
|
|
|
|
|
PhabricatorPolicyFilter::requireCapability(
|
|
|
|
$viewer,
|
|
|
|
$repository,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
|
|
|
|
$is_svn = false;
|
|
|
|
$is_git = false;
|
|
|
|
$is_hg = false;
|
|
|
|
switch ($repository->getVersionControlSystem()) {
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
|
|
|
$is_git = true;
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
|
|
|
$is_svn = true;
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
|
|
|
$is_hg = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
$has_branches = ($is_git || $is_hg);
|
2013-10-30 21:15:32 +01:00
|
|
|
$has_local = $repository->usesLocalWorkingCopy();
|
2013-10-26 00:58:58 +02:00
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
$crumbs = $this->buildApplicationCrumbs($is_main = true);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$title = pht('Edit %s', $repository->getName());
|
|
|
|
|
|
|
|
$header = id(new PHUIHeaderView())
|
|
|
|
->setHeader($title);
|
2013-10-29 20:24:03 +01:00
|
|
|
if ($repository->isTracked()) {
|
2014-05-19 01:10:54 +02:00
|
|
|
$header->setStatus('fa-check', 'bluegrey', pht('Active'));
|
2013-10-29 20:24:03 +01:00
|
|
|
} else {
|
2014-05-19 01:10:54 +02:00
|
|
|
$header->setStatus('fa-ban', 'dark', pht('Inactive'));
|
2013-10-26 00:58:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$basic_actions = $this->buildBasicActions($repository);
|
|
|
|
$basic_properties =
|
|
|
|
$this->buildBasicProperties($repository, $basic_actions);
|
|
|
|
|
|
|
|
$policy_actions = $this->buildPolicyActions($repository);
|
|
|
|
$policy_properties =
|
|
|
|
$this->buildPolicyProperties($repository, $policy_actions);
|
|
|
|
|
2013-11-02 01:39:35 +01:00
|
|
|
$remote_properties = null;
|
|
|
|
if (!$repository->isHosted()) {
|
|
|
|
$remote_properties = $this->buildRemoteProperties(
|
|
|
|
$repository,
|
|
|
|
$this->buildRemoteActions($repository));
|
|
|
|
}
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$encoding_actions = $this->buildEncodingActions($repository);
|
|
|
|
$encoding_properties =
|
|
|
|
$this->buildEncodingProperties($repository, $encoding_actions);
|
|
|
|
|
2013-10-26 05:13:38 +02:00
|
|
|
$hosting_properties = $this->buildHostingProperties(
|
|
|
|
$repository,
|
|
|
|
$this->buildHostingActions($repository));
|
|
|
|
|
2013-11-23 00:23:50 +01:00
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
$branches_properties = null;
|
|
|
|
if ($has_branches) {
|
|
|
|
$branches_properties = $this->buildBranchesProperties(
|
|
|
|
$repository,
|
|
|
|
$this->buildBranchesActions($repository));
|
|
|
|
}
|
|
|
|
|
|
|
|
$subversion_properties = null;
|
|
|
|
if ($is_svn) {
|
|
|
|
$subversion_properties = $this->buildSubversionProperties(
|
|
|
|
$repository,
|
|
|
|
$this->buildSubversionActions($repository));
|
|
|
|
}
|
|
|
|
|
2014-12-17 20:13:49 +01:00
|
|
|
$storage_properties = null;
|
2013-10-29 20:20:26 +01:00
|
|
|
if ($has_local) {
|
2014-12-17 20:13:49 +01:00
|
|
|
$storage_properties = $this->buildStorageProperties(
|
2013-10-29 20:20:26 +01:00
|
|
|
$repository,
|
2014-12-17 20:13:49 +01:00
|
|
|
$this->buildStorageActions($repository));
|
2013-10-29 20:20:26 +01:00
|
|
|
}
|
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
$actions_properties = $this->buildActionsProperties(
|
|
|
|
$repository,
|
|
|
|
$this->buildActionsActions($repository));
|
|
|
|
|
Transactions - deploy buildTransactionTimeline to remaining applications
Summary:
Ref T4712. Specifically...
- Differential
- needed getApplicationTransactionViewObject() implemented
- Audit
- needed getApplicationTransactionViewObject() implemented
- Repository
- one object needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true)
- Ponder
- BONUS BUG FIX - leaving a comment on an answer had a bad redirect URI
- both PonderQuestion and PonderAnswer needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on both "history" controllers
- left a "TODO" on buildAnswers on the question view controller, which is non-standard and should be re-written eventually
- Phortune
- BONUS BUG FIX - fix new user "createNewAccount" code to not fatal
- PhortuneAccount, PhortuneMerchant, and PhortuneCart needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on Account view, merchant view, and cart view controller
- Fund
- Legalpad
- Nuance
- NuanceSource needed PhabricatorApplicationTransactionInterface implemented
- Releeph (this product is kind of a mess...)
- HACKQUEST - had to manually create an arcanist project to even be able to make a "product" and get started...!
- BONUS BUG FIX - make sure to "setName" on product edit
- ReleephProject (should be ReleepProduct...?), ReleephBranch, and ReleepRequest needed PhabricatorApplicationTransactionInterface implemented
- Harbormaster
- HarbormasterBuildable, HarbormasterBuild, HarbormasterBuildPlan, and HarbormasterBuildStep all needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) all over the place
Test Plan: foreach application, viewed the timeline(s) and made sure they still rendered
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T4712
Differential Revision: https://secure.phabricator.com/D10925
2014-12-04 00:35:47 +01:00
|
|
|
$timeline = $this->buildTransactionTimeline(
|
|
|
|
$repository,
|
|
|
|
new PhabricatorRepositoryTransactionQuery());
|
|
|
|
$timeline->setShouldTerminate(true);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes = array();
|
|
|
|
|
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
2013-10-26 00:58:58 +02:00
|
|
|
->setHeader($header)
|
2013-11-23 00:23:50 +01:00
|
|
|
->addPropertyList($basic_properties);
|
|
|
|
|
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Policies'))
|
|
|
|
->addPropertyList($policy_properties);
|
|
|
|
|
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Hosting'))
|
2013-11-02 01:39:35 +01:00
|
|
|
->addPropertyList($hosting_properties);
|
|
|
|
|
2013-11-23 00:23:50 +01:00
|
|
|
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');
|
|
|
|
|
Add "phabricator.silent" for stopping all outbound events from an install
Summary:
Ref T7522. This is mostly useful in the cluster, but could be useful for external installs too.
If you want to import an instance into a test/dry-run state (in the cluster, to test an import; in the general case, to do something like test new hardware or configuration), you currently risk spamming users with a lot of duplicate notifications. In particular, if Phabricator tracks remotes, both instances will continue importing commits and sending email about them. Both instances will try to publish to mirrors, too, which could be bad news, and both instances will try to update linked services.
Instead, provide a flag to let an instance run in "silent mode", which disables all outbound messaging and data.
We need to remember to support this flag on any new outbound channels, but we add about one of those per year so I think that's reasonable.
Test Plan:
- Flipped config.
- Saw it void email, feed and mirroring.
- Didn't test SMS since it's not really in use yet and not convenient to test.
- (Can you think of any publishing I missed?)
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T7522
Differential Revision: https://secure.phabricator.com/D12109
2015-03-18 15:09:43 +01:00
|
|
|
$mirror_info = array();
|
|
|
|
if (PhabricatorEnv::getEnvConfig('phabricator.silent')) {
|
|
|
|
$mirror_info[] = pht(
|
|
|
|
'Phabricator is running in silent mode, so changes will not '.
|
|
|
|
'be pushed to mirrors.');
|
|
|
|
}
|
|
|
|
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
Add "phabricator.silent" for stopping all outbound events from an install
Summary:
Ref T7522. This is mostly useful in the cluster, but could be useful for external installs too.
If you want to import an instance into a test/dry-run state (in the cluster, to test an import; in the general case, to do something like test new hardware or configuration), you currently risk spamming users with a lot of duplicate notifications. In particular, if Phabricator tracks remotes, both instances will continue importing commits and sending email about them. Both instances will try to publish to mirrors, too, which could be bad news, and both instances will try to update linked services.
Instead, provide a flag to let an instance run in "silent mode", which disables all outbound messaging and data.
We need to remember to support this flag on any new outbound channels, but we add about one of those per year so I think that's reasonable.
Test Plan:
- Flipped config.
- Saw it void email, feed and mirroring.
- Didn't test SMS since it's not really in use yet and not convenient to test.
- (Can you think of any publishing I missed?)
Reviewers: btrahan
Reviewed By: btrahan
Subscribers: epriestley
Maniphest Tasks: T7522
Differential Revision: https://secure.phabricator.com/D12109
2015-03-18 15:09:43 +01:00
|
|
|
->setFormErrors($mirror_info)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setHeaderText(pht('Mirrors'))
|
|
|
|
->addPropertyList($mirror_properties);
|
|
|
|
|
|
|
|
$boxes[] = $mirror_list;
|
|
|
|
}
|
|
|
|
|
2013-11-02 01:39:35 +01:00
|
|
|
if ($remote_properties) {
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Remote'))
|
|
|
|
->addPropertyList($remote_properties);
|
2013-11-02 01:39:35 +01:00
|
|
|
}
|
2013-10-29 20:20:26 +01:00
|
|
|
|
2014-12-17 20:13:49 +01:00
|
|
|
if ($storage_properties) {
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
2014-12-17 20:13:49 +01:00
|
|
|
->setHeaderText(pht('Storage'))
|
|
|
|
->addPropertyList($storage_properties);
|
2013-10-29 20:20:26 +01:00
|
|
|
}
|
|
|
|
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Text Encoding'))
|
|
|
|
->addPropertyList($encoding_properties);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
if ($branches_properties) {
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Branches'))
|
|
|
|
->addPropertyList($branches_properties);
|
2013-10-26 00:58:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($subversion_properties) {
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Subversion'))
|
|
|
|
->addPropertyList($subversion_properties);
|
2013-10-26 00:58:58 +02:00
|
|
|
}
|
|
|
|
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes[] = id(new PHUIObjectBoxView())
|
|
|
|
->setHeaderText(pht('Actions'))
|
|
|
|
->addPropertyList($actions_properties);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
return $this->buildApplicationPage(
|
|
|
|
array(
|
|
|
|
$crumbs,
|
2013-11-23 00:23:50 +01:00
|
|
|
$boxes,
|
Transactions - deploy buildTransactionTimeline to remaining applications
Summary:
Ref T4712. Specifically...
- Differential
- needed getApplicationTransactionViewObject() implemented
- Audit
- needed getApplicationTransactionViewObject() implemented
- Repository
- one object needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true)
- Ponder
- BONUS BUG FIX - leaving a comment on an answer had a bad redirect URI
- both PonderQuestion and PonderAnswer needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on both "history" controllers
- left a "TODO" on buildAnswers on the question view controller, which is non-standard and should be re-written eventually
- Phortune
- BONUS BUG FIX - fix new user "createNewAccount" code to not fatal
- PhortuneAccount, PhortuneMerchant, and PhortuneCart needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) on Account view, merchant view, and cart view controller
- Fund
- Legalpad
- Nuance
- NuanceSource needed PhabricatorApplicationTransactionInterface implemented
- Releeph (this product is kind of a mess...)
- HACKQUEST - had to manually create an arcanist project to even be able to make a "product" and get started...!
- BONUS BUG FIX - make sure to "setName" on product edit
- ReleephProject (should be ReleepProduct...?), ReleephBranch, and ReleepRequest needed PhabricatorApplicationTransactionInterface implemented
- Harbormaster
- HarbormasterBuildable, HarbormasterBuild, HarbormasterBuildPlan, and HarbormasterBuildStep all needed PhabricatorApplicationTransactionInterface implemented
- setShouldTerminate(true) all over the place
Test Plan: foreach application, viewed the timeline(s) and made sure they still rendered
Reviewers: epriestley
Reviewed By: epriestley
Subscribers: Korvin, epriestley
Maniphest Tasks: T4712
Differential Revision: https://secure.phabricator.com/D10925
2014-12-04 00:35:47 +01:00
|
|
|
$timeline,
|
2013-10-26 00:58:58 +02:00
|
|
|
),
|
|
|
|
array(
|
|
|
|
'title' => $title,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildBasicActions(PhabricatorRepository $repository) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Edit Basic Information'))
|
|
|
|
->setHref($this->getRepositoryControllerURI($repository, 'edit/basic/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
2014-08-21 20:30:12 +02:00
|
|
|
$edit = id(new PhabricatorActionView())
|
|
|
|
->setIcon('fa-refresh')
|
|
|
|
->setName(pht('Update Now'))
|
|
|
|
->setWorkflow(true)
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/update/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
$activate = id(new PhabricatorActionView())
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/activate/'))
|
|
|
|
->setWorkflow(true);
|
|
|
|
|
|
|
|
if ($repository->isTracked()) {
|
|
|
|
$activate
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pause')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Deactivate Repository'));
|
|
|
|
} else {
|
|
|
|
$activate
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-play')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Activate Repository'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$view->addAction($activate);
|
|
|
|
|
2013-10-29 20:26:07 +01:00
|
|
|
$view->addAction(
|
|
|
|
id(new PhabricatorActionView())
|
|
|
|
->setName(pht('Delete Repository'))
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-times')
|
2013-10-29 20:26:07 +01:00
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/delete/'))
|
2013-12-30 23:28:43 +01:00
|
|
|
->setDisabled(true)
|
2013-10-29 20:26:07 +01:00
|
|
|
->setWorkflow(true));
|
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildBasicProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
|
|
|
->setActionList($actions);
|
|
|
|
|
|
|
|
$type = PhabricatorRepositoryType::getNameForRepositoryType(
|
|
|
|
$repository->getVersionControlSystem());
|
|
|
|
|
|
|
|
$view->addProperty(pht('Type'), $type);
|
|
|
|
$view->addProperty(pht('Callsign'), $repository->getCallsign());
|
|
|
|
|
2014-01-30 20:42:10 +01:00
|
|
|
|
|
|
|
$clone_name = $repository->getDetail('clone-name');
|
|
|
|
|
2014-02-28 22:04:41 +01:00
|
|
|
if ($repository->isHosted()) {
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Clone/Checkout As'),
|
|
|
|
$clone_name
|
|
|
|
? $clone_name.'/'
|
|
|
|
: phutil_tag('em', array(), $repository->getCloneName().'/'));
|
|
|
|
}
|
2014-01-30 20:42:10 +01:00
|
|
|
|
2014-01-03 21:24:09 +01:00
|
|
|
$project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
|
|
|
$repository->getPHID(),
|
2014-07-18 00:42:19 +02:00
|
|
|
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
2014-01-03 21:24:09 +01:00
|
|
|
if ($project_phids) {
|
|
|
|
$this->loadHandles($project_phids);
|
2014-04-09 04:48:31 +02:00
|
|
|
$project_text = $this->renderHandlesForPHIDs($project_phids);
|
|
|
|
} else {
|
|
|
|
$project_text = phutil_tag('em', array(), pht('None'));
|
2014-01-03 21:24:09 +01:00
|
|
|
}
|
2014-04-09 04:48:31 +02:00
|
|
|
$view->addProperty(
|
|
|
|
pht('Projects'),
|
|
|
|
$project_text);
|
2014-01-03 21:24:09 +01:00
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
$view->addProperty(
|
|
|
|
pht('Status'),
|
|
|
|
$this->buildRepositoryStatus($repository));
|
|
|
|
|
2014-08-21 20:30:12 +02:00
|
|
|
$view->addProperty(
|
|
|
|
pht('Update Frequency'),
|
|
|
|
$this->buildRepositoryUpdateInterval($repository));
|
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
$description = $repository->getDetail('description');
|
|
|
|
$view->addSectionHeader(pht('Description'));
|
|
|
|
if (!strlen($description)) {
|
|
|
|
$description = phutil_tag('em', array(), pht('No description provided.'));
|
|
|
|
} else {
|
|
|
|
$description = PhabricatorMarkupEngine::renderOneObject(
|
|
|
|
$repository,
|
|
|
|
'description',
|
|
|
|
$viewer);
|
|
|
|
}
|
|
|
|
$view->addTextContent($description);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildEncodingActions(PhabricatorRepository $repository) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Edit Text Encoding'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/encoding/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildEncodingProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$encoding = $repository->getDetail('encoding');
|
|
|
|
if (!$encoding) {
|
|
|
|
$encoding = phutil_tag('em', array(), pht('Use Default (UTF-8)'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$view->addProperty(pht('Encoding'), $encoding);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildPolicyActions(PhabricatorRepository $repository) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Edit Policies'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/policy/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildPolicyProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$descriptions = PhabricatorPolicyQuery::renderPolicyDescriptions(
|
|
|
|
$viewer,
|
|
|
|
$repository);
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Visible To'),
|
|
|
|
$descriptions[PhabricatorPolicyCapability::CAN_VIEW]);
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Editable By'),
|
|
|
|
$descriptions[PhabricatorPolicyCapability::CAN_EDIT]);
|
|
|
|
|
2013-10-26 05:13:38 +02:00
|
|
|
$pushable = $repository->isHosted()
|
2014-07-25 00:20:39 +02:00
|
|
|
? $descriptions[DiffusionPushCapability::CAPABILITY]
|
2013-10-26 05:13:38 +02:00
|
|
|
: phutil_tag('em', array(), pht('Not a Hosted Repository'));
|
|
|
|
$view->addProperty(pht('Pushable By'), $pushable);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildBranchesActions(PhabricatorRepository $repository) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Edit Branches'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/branches/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildBranchesProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$default_branch = nonempty(
|
|
|
|
$repository->getHumanReadableDetail('default-branch'),
|
|
|
|
phutil_tag('em', array(), $repository->getDefaultBranch()));
|
|
|
|
$view->addProperty(pht('Default Branch'), $default_branch);
|
|
|
|
|
|
|
|
$track_only = nonempty(
|
2013-10-26 02:46:08 +02:00
|
|
|
$repository->getHumanReadableDetail('branch-filter', array()),
|
2013-10-26 00:58:58 +02:00
|
|
|
phutil_tag('em', array(), pht('Track All Branches')));
|
|
|
|
$view->addProperty(pht('Track Only'), $track_only);
|
|
|
|
|
|
|
|
$autoclose_only = nonempty(
|
2013-10-26 02:46:08 +02:00
|
|
|
$repository->getHumanReadableDetail('close-commits-filter', array()),
|
2013-10-26 00:58:58 +02:00
|
|
|
phutil_tag('em', array(), pht('Autoclose On All Branches')));
|
2013-11-02 01:35:43 +01:00
|
|
|
|
|
|
|
if ($repository->getDetail('disable-autoclose')) {
|
|
|
|
$autoclose_only = phutil_tag('em', array(), pht('Disabled'));
|
|
|
|
}
|
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
$view->addProperty(pht('Autoclose Only'), $autoclose_only);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildSubversionActions(PhabricatorRepository $repository) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Edit Subversion Info'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/subversion/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildSubversionProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$svn_uuid = nonempty(
|
|
|
|
$repository->getUUID(),
|
|
|
|
phutil_tag('em', array(), pht('Not Configured')));
|
|
|
|
$view->addProperty(pht('Subversion UUID'), $svn_uuid);
|
|
|
|
|
|
|
|
$svn_subpath = nonempty(
|
|
|
|
$repository->getHumanReadableDetail('svn-subpath'),
|
|
|
|
phutil_tag('em', array(), pht('Import Entire Repository')));
|
|
|
|
$view->addProperty(pht('Import Only'), $svn_subpath);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildActionsActions(PhabricatorRepository $repository) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Edit Actions'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/actions/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildActionsProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$notify = $repository->getDetail('herald-disabled')
|
|
|
|
? pht('Off')
|
|
|
|
: pht('On');
|
|
|
|
$notify = phutil_tag('em', array(), $notify);
|
|
|
|
$view->addProperty(pht('Publish/Notify'), $notify);
|
|
|
|
|
|
|
|
$autoclose = $repository->getDetail('disable-autoclose')
|
|
|
|
? pht('Off')
|
|
|
|
: pht('On');
|
|
|
|
$autoclose = phutil_tag('em', array(), $autoclose);
|
|
|
|
$view->addProperty(pht('Autoclose'), $autoclose);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildRemoteActions(PhabricatorRepository $repository) {
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 00:58:58 +02:00
|
|
|
->setName(pht('Edit Remote'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/remote/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildRemoteProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-26 00:58:58 +02:00
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Remote URI'),
|
2013-10-29 20:20:26 +01:00
|
|
|
$repository->getHumanReadableDetail('remote-uri'));
|
2013-10-26 00:58:58 +02:00
|
|
|
|
2013-11-23 00:23:33 +01:00
|
|
|
$credential_phid = $repository->getCredentialPHID();
|
|
|
|
if ($credential_phid) {
|
|
|
|
$this->loadHandles(array($credential_phid));
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Credential'),
|
|
|
|
$this->getHandle($credential_phid)->renderLink());
|
|
|
|
}
|
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2014-12-17 20:13:49 +01:00
|
|
|
private function buildStorageActions(PhabricatorRepository $repository) {
|
2013-10-29 20:20:26 +01:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($viewer);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2014-12-17 20:13:49 +01:00
|
|
|
->setName(pht('Edit Storage'))
|
2013-10-29 20:20:26 +01:00
|
|
|
->setHref(
|
2014-12-17 20:13:49 +01:00
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/storage/'));
|
2013-10-29 20:20:26 +01:00
|
|
|
$view->addAction($edit);
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2014-12-17 20:13:49 +01:00
|
|
|
private function buildStorageProperties(
|
2013-10-29 20:20:26 +01:00
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$viewer = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($viewer)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-29 20:20:26 +01:00
|
|
|
|
2014-12-18 23:31:22 +01:00
|
|
|
$service_phid = $repository->getAlmanacServicePHID();
|
|
|
|
if ($service_phid) {
|
|
|
|
$handles = $this->loadViewerHandles(array($service_phid));
|
|
|
|
$v_service = $handles[$service_phid]->renderLink();
|
|
|
|
} else {
|
|
|
|
$v_service = phutil_tag(
|
|
|
|
'em',
|
|
|
|
array(),
|
|
|
|
pht('Local'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Storage Service'),
|
|
|
|
$v_service);
|
|
|
|
|
2013-10-29 20:20:26 +01:00
|
|
|
$view->addProperty(
|
2014-12-17 20:13:49 +01:00
|
|
|
pht('Storage Path'),
|
2013-10-29 20:20:26 +01:00
|
|
|
$repository->getHumanReadableDetail('local-path'));
|
|
|
|
|
|
|
|
return $view;
|
|
|
|
}
|
2013-10-26 05:13:38 +02:00
|
|
|
|
|
|
|
private function buildHostingActions(PhabricatorRepository $repository) {
|
|
|
|
$user = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PhabricatorActionListView())
|
|
|
|
->setObjectURI($this->getRequest()->getRequestURI())
|
|
|
|
->setUser($user);
|
|
|
|
|
|
|
|
$edit = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-10-26 05:13:38 +02:00
|
|
|
->setName(pht('Edit Hosting'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/hosting/'));
|
|
|
|
$view->addAction($edit);
|
|
|
|
|
2013-12-03 19:28:39 +01:00
|
|
|
if ($repository->canAllowDangerousChanges()) {
|
|
|
|
if ($repository->shouldAllowDangerousChanges()) {
|
|
|
|
$changes = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-shield')
|
2013-12-03 19:28:39 +01:00
|
|
|
->setName(pht('Prevent Dangerous Changes'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/dangerous/'))
|
|
|
|
->setWorkflow(true);
|
|
|
|
} else {
|
|
|
|
$changes = id(new PhabricatorActionView())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-bullseye')
|
2013-12-03 19:28:39 +01:00
|
|
|
->setName(pht('Allow Dangerous Changes'))
|
|
|
|
->setHref(
|
|
|
|
$this->getRepositoryControllerURI($repository, 'edit/dangerous/'))
|
|
|
|
->setWorkflow(true);
|
|
|
|
}
|
|
|
|
$view->addAction($changes);
|
|
|
|
}
|
|
|
|
|
2013-10-26 05:13:38 +02:00
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildHostingProperties(
|
|
|
|
PhabricatorRepository $repository,
|
|
|
|
PhabricatorActionListView $actions) {
|
|
|
|
|
|
|
|
$user = $this->getRequest()->getUser();
|
|
|
|
|
|
|
|
$view = id(new PHUIPropertyListView())
|
|
|
|
->setUser($user)
|
2013-11-23 00:23:50 +01:00
|
|
|
->setActionList($actions);
|
2013-10-26 05:13:38 +02:00
|
|
|
|
|
|
|
$hosting = $repository->isHosted()
|
|
|
|
? pht('Hosted on Phabricator')
|
|
|
|
: pht('Hosted Elsewhere');
|
|
|
|
$view->addProperty(pht('Hosting'), phutil_tag('em', array(), $hosting));
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Serve over HTTP'),
|
|
|
|
phutil_tag(
|
|
|
|
'em',
|
|
|
|
array(),
|
|
|
|
PhabricatorRepository::getProtocolAvailabilityName(
|
|
|
|
$repository->getServeOverHTTP())));
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Serve over SSH'),
|
|
|
|
phutil_tag(
|
|
|
|
'em',
|
|
|
|
array(),
|
|
|
|
PhabricatorRepository::getProtocolAvailabilityName(
|
|
|
|
$repository->getServeOverSSH())));
|
|
|
|
|
2013-12-03 19:28:39 +01:00
|
|
|
if ($repository->canAllowDangerousChanges()) {
|
|
|
|
if ($repository->shouldAllowDangerousChanges()) {
|
|
|
|
$description = pht('Allowed');
|
|
|
|
} else {
|
|
|
|
$description = pht('Not Allowed');
|
|
|
|
}
|
|
|
|
|
|
|
|
$view->addProperty(
|
|
|
|
pht('Dangerous Changes'),
|
|
|
|
$description);
|
|
|
|
}
|
|
|
|
|
2013-10-26 05:13:38 +02:00
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
private function buildRepositoryStatus(
|
|
|
|
PhabricatorRepository $repository) {
|
|
|
|
|
2013-10-31 23:46:57 +01:00
|
|
|
$viewer = $this->getRequest()->getUser();
|
2014-12-31 20:50:35 +01:00
|
|
|
$is_cluster = $repository->getAlmanacServicePHID();
|
2013-10-31 23:46:57 +01:00
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
$view = new PHUIStatusListView();
|
|
|
|
|
2013-10-31 00:04:19 +01:00
|
|
|
$messages = id(new PhabricatorRepositoryStatusMessage())
|
|
|
|
->loadAllWhere('repositoryID = %d', $repository->getID());
|
|
|
|
$messages = mpull($messages, null, 'getStatusType');
|
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
if ($repository->isTracked()) {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
2013-10-30 21:15:32 +01:00
|
|
|
->setTarget(pht('Repository Active')));
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')
|
2013-10-30 21:15:32 +01:00
|
|
|
->setTarget(pht('Repository Inactive'))
|
|
|
|
->setNote(
|
|
|
|
pht('Activate this repository to begin or resume import.')));
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2013-11-05 00:14:01 +01:00
|
|
|
$binaries = array();
|
2014-04-04 21:47:10 +02:00
|
|
|
$svnlook_check = false;
|
2013-11-05 00:14:01 +01:00
|
|
|
switch ($repository->getVersionControlSystem()) {
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
|
|
|
$binaries[] = 'git';
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
|
|
|
$binaries[] = 'svn';
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
|
|
|
$binaries[] = 'hg';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2013-11-05 00:03:07 +01:00
|
|
|
if ($repository->isHosted()) {
|
|
|
|
if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) {
|
|
|
|
switch ($repository->getVersionControlSystem()) {
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
2013-11-05 00:14:01 +01:00
|
|
|
$binaries[] = 'git-http-backend';
|
2013-11-05 00:03:07 +01:00
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
2013-11-05 00:14:01 +01:00
|
|
|
$binaries[] = 'svnserve';
|
|
|
|
$binaries[] = 'svnadmin';
|
2014-04-04 21:47:10 +02:00
|
|
|
$binaries[] = 'svnlook';
|
|
|
|
$svnlook_check = true;
|
2013-11-05 00:03:07 +01:00
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
2013-11-05 00:14:01 +01:00
|
|
|
$binaries[] = 'hg';
|
2013-11-05 00:03:07 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) {
|
|
|
|
switch ($repository->getVersionControlSystem()) {
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
|
2013-11-05 00:14:01 +01:00
|
|
|
$binaries[] = 'git-receive-pack';
|
|
|
|
$binaries[] = 'git-upload-pack';
|
2013-11-05 00:03:07 +01:00
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
|
2013-11-05 00:14:01 +01:00
|
|
|
$binaries[] = 'svnserve';
|
|
|
|
$binaries[] = 'svnadmin';
|
2014-04-04 21:47:10 +02:00
|
|
|
$binaries[] = 'svnlook';
|
|
|
|
$svnlook_check = true;
|
2013-11-05 00:03:07 +01:00
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
|
2013-11-05 00:14:01 +01:00
|
|
|
$binaries[] = 'hg';
|
2013-11-05 00:03:07 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-11-05 00:14:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$binaries = array_unique($binaries);
|
2014-12-31 20:50:35 +01:00
|
|
|
if (!$is_cluster) {
|
|
|
|
// We're only checking for binaries if we aren't running with a cluster
|
|
|
|
// configuration. In theory, we could check for binaries on the
|
|
|
|
// repository host machine, but we'd need to make this more complicated
|
|
|
|
// to do that.
|
|
|
|
|
|
|
|
foreach ($binaries as $binary) {
|
|
|
|
$where = Filesystem::resolveBinary($binary);
|
|
|
|
if (!$where) {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
|
|
|
->setTarget(
|
|
|
|
pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))
|
|
|
|
->setNote(pht(
|
|
|
|
"Unable to find this binary in the webserver's PATH. You may ".
|
|
|
|
"need to configure %s.",
|
|
|
|
$this->getEnvConfigLink())));
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
|
|
|
->setTarget(
|
|
|
|
pht('Found Binary %s', phutil_tag('tt', array(), $binary)))
|
|
|
|
->setNote(phutil_tag('tt', array(), $where)));
|
|
|
|
}
|
2013-11-05 00:03:07 +01:00
|
|
|
}
|
|
|
|
|
2014-12-31 20:50:35 +01:00
|
|
|
// This gets checked generically above. However, for svn commit hooks, we
|
|
|
|
// need this to be in environment.append-paths because subversion strips
|
|
|
|
// PATH.
|
|
|
|
if ($svnlook_check) {
|
|
|
|
$where = Filesystem::resolveBinary('svnlook');
|
|
|
|
if ($where) {
|
|
|
|
$path = substr($where, 0, strlen($where) - strlen('svnlook'));
|
|
|
|
$dirs = PhabricatorEnv::getEnvConfig('environment.append-paths');
|
|
|
|
$in_path = false;
|
|
|
|
foreach ($dirs as $dir) {
|
|
|
|
if (Filesystem::isDescendant($path, $dir)) {
|
|
|
|
$in_path = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!$in_path) {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
|
|
|
->setTarget(
|
|
|
|
pht('Missing Binary %s', phutil_tag('tt', array(), $binary)))
|
|
|
|
->setNote(pht(
|
|
|
|
'Unable to find this binary in `environment.append-paths`. '.
|
|
|
|
'You need to configure %s and include %s.',
|
|
|
|
$this->getEnvConfigLink(),
|
|
|
|
$path)));
|
2014-04-04 21:47:10 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-17 23:01:31 +01:00
|
|
|
$doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
|
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
$daemon_instructions = pht(
|
|
|
|
'Use %s to start daemons. See %s.',
|
|
|
|
phutil_tag('tt', array(), 'bin/phd start'),
|
|
|
|
phutil_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $doc_href,
|
|
|
|
),
|
|
|
|
pht('Managing Daemons with phd')));
|
|
|
|
|
|
|
|
|
|
|
|
$pull_daemon = id(new PhabricatorDaemonLogQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
|
|
|
|
->withDaemonClasses(array('PhabricatorRepositoryPullLocalDaemon'))
|
|
|
|
->setLimit(1)
|
|
|
|
->execute();
|
|
|
|
|
|
|
|
if ($pull_daemon) {
|
2014-12-31 20:50:35 +01:00
|
|
|
|
|
|
|
// TODO: In a cluster environment, we need a daemon on this repository's
|
|
|
|
// host, specifically, and we aren't checking for that right now. This
|
|
|
|
// is a reasonable proxy for things being more-or-less correctly set up,
|
|
|
|
// though.
|
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
2013-10-30 21:15:32 +01:00
|
|
|
->setTarget(pht('Pull Daemon Running')));
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
2013-10-30 21:15:32 +01:00
|
|
|
->setTarget(pht('Pull Daemon Not Running'))
|
|
|
|
->setNote($daemon_instructions));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
$task_daemon = id(new PhabricatorDaemonLogQuery())
|
|
|
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
|
|
->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)
|
|
|
|
->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))
|
|
|
|
->setLimit(1)
|
|
|
|
->execute();
|
|
|
|
if ($task_daemon) {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
2013-10-30 21:15:32 +01:00
|
|
|
->setTarget(pht('Task Daemon Running')));
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
2013-10-30 21:15:32 +01:00
|
|
|
->setTarget(pht('Task Daemon Not Running'))
|
|
|
|
->setNote($daemon_instructions));
|
|
|
|
}
|
|
|
|
|
2014-12-31 20:50:35 +01:00
|
|
|
|
|
|
|
if ($is_cluster) {
|
|
|
|
// Just omit this status check for now in cluster environments. We
|
|
|
|
// could make a service call and pull it from the repository host
|
|
|
|
// eventually.
|
|
|
|
} else if ($repository->usesLocalWorkingCopy()) {
|
2013-11-05 19:01:44 +01:00
|
|
|
$local_parent = dirname($repository->getLocalPath());
|
|
|
|
if (Filesystem::pathExists($local_parent)) {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
2013-11-05 19:01:44 +01:00
|
|
|
->setTarget(pht('Storage Directory OK'))
|
|
|
|
->setNote(phutil_tag('tt', array(), $local_parent)));
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
2013-11-05 19:01:44 +01:00
|
|
|
->setTarget(pht('No Storage Directory'))
|
|
|
|
->setNote(
|
|
|
|
pht(
|
|
|
|
'Storage directory %s does not exist, or is not readable by '.
|
|
|
|
'the webserver. Create this directory or make it readable.',
|
|
|
|
phutil_tag('tt', array(), $local_parent))));
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
$local_path = $repository->getLocalPath();
|
2013-10-31 00:04:19 +01:00
|
|
|
$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT);
|
|
|
|
if ($message) {
|
|
|
|
switch ($message->getStatusCode()) {
|
|
|
|
case PhabricatorRepositoryStatusMessage::CODE_ERROR:
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
2013-10-31 00:04:19 +01:00
|
|
|
->setTarget(pht('Initialization Error'))
|
|
|
|
->setNote($message->getParameter('message')));
|
|
|
|
return $view;
|
|
|
|
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
|
|
|
|
if (Filesystem::pathExists($local_path)) {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
2013-10-31 00:04:19 +01:00
|
|
|
->setTarget(pht('Working Copy OK'))
|
|
|
|
->setNote(phutil_tag('tt', array(), $local_path)));
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
2013-10-31 00:04:19 +01:00
|
|
|
->setTarget(pht('Working Copy Error'))
|
|
|
|
->setNote(
|
|
|
|
pht(
|
|
|
|
'Working copy %s has been deleted, or is not '.
|
|
|
|
'readable by the webserver. Make this directory '.
|
|
|
|
'readable. If it has been deleted, the daemons should '.
|
|
|
|
'restore it automatically.',
|
|
|
|
phutil_tag('tt', array(), $local_path))));
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PhabricatorRepositoryStatusMessage::CODE_WORKING:
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
|
2013-10-31 00:04:19 +01:00
|
|
|
->setTarget(pht('Initializing Working Copy'))
|
2013-10-31 23:46:57 +01:00
|
|
|
->setNote(pht('Daemons are initializing the working copy.')));
|
2013-10-31 00:04:19 +01:00
|
|
|
return $view;
|
|
|
|
default:
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
2013-10-31 00:04:19 +01:00
|
|
|
->setTarget(pht('Unknown Init Status'))
|
|
|
|
->setNote($message->getStatusCode()));
|
|
|
|
return $view;
|
|
|
|
}
|
2013-10-30 21:15:32 +01:00
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
|
2013-10-30 21:15:32 +01:00
|
|
|
->setTarget(pht('No Working Copy Yet'))
|
|
|
|
->setNote(
|
|
|
|
pht('Waiting for daemons to build a working copy.')));
|
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-31 23:46:57 +01:00
|
|
|
$message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);
|
|
|
|
if ($message) {
|
|
|
|
switch ($message->getStatusCode()) {
|
|
|
|
case PhabricatorRepositoryStatusMessage::CODE_ERROR:
|
2015-02-19 19:32:25 +01:00
|
|
|
$message = $message->getParameter('message');
|
|
|
|
|
|
|
|
$suggestion = null;
|
|
|
|
if (preg_match('/Permission denied \(publickey\)./', $message)) {
|
|
|
|
$suggestion = pht(
|
|
|
|
'Public Key Error: This error usually indicates that the '.
|
|
|
|
'keypair you have configured does not have permission to '.
|
|
|
|
'access the repository.');
|
|
|
|
}
|
|
|
|
|
|
|
|
$message = phutil_escape_html_newlines($message);
|
|
|
|
|
|
|
|
if ($suggestion !== null) {
|
|
|
|
$message = array(
|
|
|
|
phutil_tag('strong', array(), $suggestion),
|
|
|
|
phutil_tag('br'),
|
|
|
|
phutil_tag('br'),
|
|
|
|
phutil_tag('em', array(), pht('Raw Error')),
|
|
|
|
phutil_tag('br'),
|
|
|
|
$message,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2013-10-31 23:46:57 +01:00
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')
|
2013-10-31 23:46:57 +01:00
|
|
|
->setTarget(pht('Update Error'))
|
2015-02-19 19:32:25 +01:00
|
|
|
->setNote($message));
|
2013-10-31 23:46:57 +01:00
|
|
|
return $view;
|
|
|
|
case PhabricatorRepositoryStatusMessage::CODE_OKAY:
|
2014-08-21 20:30:12 +02:00
|
|
|
$ago = (PhabricatorTime::getNow() - $message->getEpoch());
|
2013-10-31 23:46:57 +01:00
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
2013-10-31 23:46:57 +01:00
|
|
|
->setTarget(pht('Updates OK'))
|
|
|
|
->setNote(
|
|
|
|
pht(
|
2014-08-21 20:30:12 +02:00
|
|
|
'Last updated %s (%s ago).',
|
|
|
|
phabricator_datetime($message->getEpoch(), $viewer),
|
|
|
|
phutil_format_relative_time_detailed($ago))));
|
2013-10-31 23:46:57 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')
|
2013-10-31 23:46:57 +01:00
|
|
|
->setTarget(pht('Waiting For Update'))
|
|
|
|
->setNote(
|
|
|
|
pht('Waiting for daemons to read updates.')));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($repository->isImporting()) {
|
|
|
|
$progress = queryfx_all(
|
|
|
|
$repository->establishConnection('r'),
|
|
|
|
'SELECT importStatus, count(*) N FROM %T WHERE repositoryID = %d
|
|
|
|
GROUP BY importStatus',
|
|
|
|
id(new PhabricatorRepositoryCommit())->getTableName(),
|
|
|
|
$repository->getID());
|
|
|
|
|
|
|
|
$done = 0;
|
|
|
|
$total = 0;
|
|
|
|
foreach ($progress as $row) {
|
|
|
|
$total += $row['N'] * 4;
|
|
|
|
$status = $row['importStatus'];
|
|
|
|
if ($status & PhabricatorRepositoryCommit::IMPORTED_MESSAGE) {
|
|
|
|
$done += $row['N'];
|
|
|
|
}
|
|
|
|
if ($status & PhabricatorRepositoryCommit::IMPORTED_CHANGE) {
|
|
|
|
$done += $row['N'];
|
|
|
|
}
|
|
|
|
if ($status & PhabricatorRepositoryCommit::IMPORTED_OWNERS) {
|
|
|
|
$done += $row['N'];
|
|
|
|
}
|
|
|
|
if ($status & PhabricatorRepositoryCommit::IMPORTED_HERALD) {
|
|
|
|
$done += $row['N'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($total) {
|
|
|
|
$percentage = 100 * ($done / $total);
|
|
|
|
} else {
|
|
|
|
$percentage = 0;
|
|
|
|
}
|
|
|
|
|
2014-01-24 21:29:13 +01:00
|
|
|
// Cap this at "99.99%", because it's confusing to users when the actual
|
|
|
|
// fraction is "99.996%" and it rounds up to "100.00%".
|
|
|
|
if ($percentage > 99.99) {
|
|
|
|
$percentage = 99.99;
|
|
|
|
}
|
|
|
|
|
|
|
|
$percentage = sprintf('%.2f%%', $percentage);
|
2013-10-31 23:46:57 +01:00
|
|
|
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')
|
2013-10-31 23:46:57 +01:00
|
|
|
->setTarget(pht('Importing'))
|
|
|
|
->setNote(
|
|
|
|
pht('%s Complete', $percentage)));
|
|
|
|
} else {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')
|
2013-10-31 23:46:57 +01:00
|
|
|
->setTarget(pht('Fully Imported')));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) {
|
|
|
|
$view->addItem(
|
|
|
|
id(new PHUIStatusItemView())
|
2014-05-17 03:59:02 +02:00
|
|
|
->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')
|
2013-10-31 23:46:57 +01:00
|
|
|
->setTarget(pht('Prioritized'))
|
2014-08-21 20:30:12 +02:00
|
|
|
->setNote(pht('This repository will be updated soon!')));
|
2013-10-31 23:46:57 +01:00
|
|
|
}
|
|
|
|
|
2013-10-30 21:15:32 +01:00
|
|
|
return $view;
|
|
|
|
}
|
|
|
|
|
2014-08-21 20:30:12 +02:00
|
|
|
private function buildRepositoryUpdateInterval(
|
|
|
|
PhabricatorRepository $repository) {
|
|
|
|
|
|
|
|
$smart_wait = $repository->loadUpdateInterval();
|
|
|
|
|
|
|
|
$doc_href = PhabricatorEnv::getDoclink(
|
|
|
|
'Diffusion User Guide: Repository Updates');
|
|
|
|
|
|
|
|
return array(
|
|
|
|
phutil_format_relative_time_detailed($smart_wait),
|
|
|
|
" \xC2\xB7 ",
|
|
|
|
phutil_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $doc_href,
|
|
|
|
'target' => '_blank',
|
|
|
|
),
|
|
|
|
pht('Learn More')),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-23 00:23:50 +01:00
|
|
|
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'))
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-plus')
|
2013-11-23 00:23:50 +01:00
|
|
|
->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())
|
2014-05-12 19:08:32 +02:00
|
|
|
->setIcon('fa-pencil')
|
2013-11-23 00:23:50 +01:00
|
|
|
->setHref($edit_uri)
|
|
|
|
->setWorkflow(true));
|
|
|
|
|
|
|
|
$item->addAction(
|
|
|
|
id(new PHUIListItemView())
|
2014-05-13 16:45:39 +02:00
|
|
|
->setIcon('fa-times')
|
2013-11-23 00:23:50 +01:00
|
|
|
->setHref($delete_uri)
|
|
|
|
->setWorkflow(true));
|
|
|
|
|
|
|
|
$mirror_list->addItem($item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return $mirror_list;
|
|
|
|
}
|
|
|
|
|
2014-04-04 21:47:10 +02:00
|
|
|
private function getEnvConfigLink() {
|
|
|
|
$config_href = '/config/edit/environment.append-paths/';
|
|
|
|
return phutil_tag(
|
|
|
|
'a',
|
|
|
|
array(
|
|
|
|
'href' => $config_href,
|
|
|
|
),
|
|
|
|
'environment.append-paths');
|
|
|
|
}
|
2013-11-23 00:23:50 +01:00
|
|
|
|
2013-10-26 00:58:58 +02:00
|
|
|
}
|