Detect and raise setup warnings from within Phabricator
Summary: This is basicaly a light version of D4286. The major problem with D4286 is that it's a huge leap and completely replaces the setup process in one step. Instead, I want to do this: - Add the post-setup warnings (yellow bar with "6 unresolved warnings..."). - Copy all setup checks into post-setup warnings (so every check has an old-style check and a new-style check). - Run that for a little bit and make sure it's stable. - Implement fatal post-setup checks (the red screen, vs the yellow bar). - Run that for a little bit. - Nuke setup mode and delete all the old checks. This should give us a bunch of very gradual steps toward the brave new world of simpler setup. Test Plan: - Faked APC setup failures, saw warnings raise. - Verified that this runs after restart (get + set). - Verified that this costs us only one cache hit after first-run (get only). Reviewers: btrahan, codeblock, vrana, chad Reviewed By: codeblock CC: aran Maniphest Tasks: T2228 Differential Revision: https://secure.phabricator.com/D4295
This commit is contained in:
		@@ -686,6 +686,8 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorConfigEntry' => 'applications/config/storage/PhabricatorConfigEntry.php',
 | 
			
		||||
    'PhabricatorConfigEntryDAO' => 'applications/config/storage/PhabricatorConfigEntryDAO.php',
 | 
			
		||||
    'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php',
 | 
			
		||||
    'PhabricatorConfigIssueListController' => 'applications/config/controller/PhabricatorConfigIssueListController.php',
 | 
			
		||||
    'PhabricatorConfigIssueViewController' => 'applications/config/controller/PhabricatorConfigIssueViewController.php',
 | 
			
		||||
    'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php',
 | 
			
		||||
    'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php',
 | 
			
		||||
    'PhabricatorConfigManagementSetWorkflow' => 'infrastructure/env/management/PhabricatorConfigManagementSetWorkflow.php',
 | 
			
		||||
@@ -1135,6 +1137,10 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorSettingsPanelSSHKeys' => 'applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php',
 | 
			
		||||
    'PhabricatorSettingsPanelSearchPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelSearchPreferences.php',
 | 
			
		||||
    'PhabricatorSetup' => 'infrastructure/PhabricatorSetup.php',
 | 
			
		||||
    'PhabricatorSetupCheck' => 'applications/config/check/PhabricatorSetupCheck.php',
 | 
			
		||||
    'PhabricatorSetupCheckAPC' => 'applications/config/check/PhabricatorSetupCheckAPC.php',
 | 
			
		||||
    'PhabricatorSetupIssue' => 'applications/config/issue/PhabricatorSetupIssue.php',
 | 
			
		||||
    'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php',
 | 
			
		||||
    'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/PhabricatorSlowvoteChoice.php',
 | 
			
		||||
    'PhabricatorSlowvoteComment' => 'applications/slowvote/storage/PhabricatorSlowvoteComment.php',
 | 
			
		||||
    'PhabricatorSlowvoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteController.php',
 | 
			
		||||
@@ -2002,6 +2008,8 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorConfigEntry' => 'PhabricatorConfigEntryDAO',
 | 
			
		||||
    'PhabricatorConfigEntryDAO' => 'PhabricatorLiskDAO',
 | 
			
		||||
    'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource',
 | 
			
		||||
    'PhabricatorConfigIssueListController' => 'PhabricatorConfigController',
 | 
			
		||||
    'PhabricatorConfigIssueViewController' => 'PhabricatorConfigController',
 | 
			
		||||
    'PhabricatorConfigListController' => 'PhabricatorConfigController',
 | 
			
		||||
    'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource',
 | 
			
		||||
    'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow',
 | 
			
		||||
@@ -2409,6 +2417,8 @@ phutil_register_library_map(array(
 | 
			
		||||
    'PhabricatorSettingsPanelProfile' => 'PhabricatorSettingsPanel',
 | 
			
		||||
    'PhabricatorSettingsPanelSSHKeys' => 'PhabricatorSettingsPanel',
 | 
			
		||||
    'PhabricatorSettingsPanelSearchPreferences' => 'PhabricatorSettingsPanel',
 | 
			
		||||
    'PhabricatorSetupCheckAPC' => 'PhabricatorSetupCheck',
 | 
			
		||||
    'PhabricatorSetupIssueView' => 'AphrontView',
 | 
			
		||||
    'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO',
 | 
			
		||||
    'PhabricatorSlowvoteComment' => 'PhabricatorSlowvoteDAO',
 | 
			
		||||
    'PhabricatorSlowvoteController' => 'PhabricatorController',
 | 
			
		||||
 
 | 
			
		||||
@@ -25,8 +25,12 @@ final class PhabricatorApplicationConfig extends PhabricatorApplication {
 | 
			
		||||
  public function getRoutes() {
 | 
			
		||||
    return array(
 | 
			
		||||
      '/config/' => array(
 | 
			
		||||
        ''                        => 'PhabricatorConfigListController',
 | 
			
		||||
        ''                          => 'PhabricatorConfigListController',
 | 
			
		||||
        'edit/(?P<key>[\w\.\-]+)/'  => 'PhabricatorConfigEditController',
 | 
			
		||||
        'issue/' => array(
 | 
			
		||||
          '' => 'PhabricatorConfigIssueListController',
 | 
			
		||||
          '(?P<key>[^/]+)/' => 'PhabricatorConfigIssueViewController',
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										79
									
								
								src/applications/config/check/PhabricatorSetupCheck.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								src/applications/config/check/PhabricatorSetupCheck.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,79 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
abstract class PhabricatorSetupCheck {
 | 
			
		||||
 | 
			
		||||
  private $issues;
 | 
			
		||||
 | 
			
		||||
  abstract protected function executeChecks();
 | 
			
		||||
 | 
			
		||||
  final protected function newIssue($key) {
 | 
			
		||||
    $issue = id(new PhabricatorSetupIssue())
 | 
			
		||||
      ->setIssueKey($key);
 | 
			
		||||
 | 
			
		||||
    $this->issues[$key] = $issue;
 | 
			
		||||
 | 
			
		||||
    return $issue;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final public function getIssues() {
 | 
			
		||||
    return $this->issues;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final public function runSetupChecks() {
 | 
			
		||||
    $this->issues = array();
 | 
			
		||||
    $this->executeChecks();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final public static function getOpenSetupIssueCount() {
 | 
			
		||||
    $cache = PhabricatorCaches::getSetupCache();
 | 
			
		||||
    return $cache->getKey('phabricator.setup.issues');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final public static function setOpenSetupIssueCount($count) {
 | 
			
		||||
    $cache = PhabricatorCaches::getSetupCache();
 | 
			
		||||
    $cache->setKey('phabricator.setup.issues', $count);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final public static function willProcessRequest() {
 | 
			
		||||
    $issue_count = self::getOpenSetupIssueCount();
 | 
			
		||||
    if ($issue_count !== null) {
 | 
			
		||||
      // We've already run setup checks, didn't hit any fatals, and then set
 | 
			
		||||
      // an issue count. This means we're good and don't need to do any extra
 | 
			
		||||
      // work.
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $issues = self::runAllChecks();
 | 
			
		||||
 | 
			
		||||
    self::setOpenSetupIssueCount(count($issues));
 | 
			
		||||
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  final public static function runAllChecks() {
 | 
			
		||||
    $symbols = id(new PhutilSymbolLoader())
 | 
			
		||||
      ->setAncestorClass('PhabricatorSetupCheck')
 | 
			
		||||
      ->setConcreteOnly(true)
 | 
			
		||||
      ->selectAndLoadSymbols();
 | 
			
		||||
 | 
			
		||||
    $checks = array();
 | 
			
		||||
    foreach ($symbols as $symbol) {
 | 
			
		||||
      $checks[] = newv($symbol['name'], array());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $issues = array();
 | 
			
		||||
    foreach ($checks as $check) {
 | 
			
		||||
      $check->runSetupChecks();
 | 
			
		||||
      foreach ($check->getIssues() as $key => $issue) {
 | 
			
		||||
        if (isset($issues[$key])) {
 | 
			
		||||
          throw new Exception(
 | 
			
		||||
            "Two setup checks raised an issue with key '{$key}'!");
 | 
			
		||||
        }
 | 
			
		||||
        $issues[$key] = $issue;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $issues;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/applications/config/check/PhabricatorSetupCheckAPC.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/applications/config/check/PhabricatorSetupCheckAPC.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class PhabricatorSetupCheckAPC extends PhabricatorSetupCheck {
 | 
			
		||||
 | 
			
		||||
  protected function executeChecks() {
 | 
			
		||||
    if (!extension_loaded('apc')) {
 | 
			
		||||
      $message = pht(
 | 
			
		||||
        "Installing the PHP extension 'APC' (Alternative PHP Cache) will ".
 | 
			
		||||
        "dramatically improve performance.");
 | 
			
		||||
 | 
			
		||||
      $this
 | 
			
		||||
        ->newIssue('extension.apc')
 | 
			
		||||
        ->setShortName(pht('APC'))
 | 
			
		||||
        ->setName(pht("PHP Extension 'APC' Not Installed"))
 | 
			
		||||
        ->setMessage($message)
 | 
			
		||||
        ->addPHPExtension('apc');
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!ini_get('apc.enabled')) {
 | 
			
		||||
      $summary = pht("Enabling APC will dramatically improve performance.");
 | 
			
		||||
      $message = pht(
 | 
			
		||||
        "The PHP extension 'APC' is installed, but not enabled in your PHP ".
 | 
			
		||||
        "configuration. Enabling it will dramatically improve Phabricator ".
 | 
			
		||||
        "performance. Edit the 'apc.enabled' setting to enable the extension.");
 | 
			
		||||
 | 
			
		||||
      $this
 | 
			
		||||
        ->newIssue('extension.apc.enabled')
 | 
			
		||||
        ->setShortName(pht('APC Disabled'))
 | 
			
		||||
        ->setName(pht("PHP Extension 'APC' Not Enabled"))
 | 
			
		||||
        ->setSummary($summary)
 | 
			
		||||
        ->setMessage($message)
 | 
			
		||||
        ->addPHPConfig('apc.enabled');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,65 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class PhabricatorConfigIssueListController
 | 
			
		||||
  extends PhabricatorConfigController {
 | 
			
		||||
 | 
			
		||||
  public function processRequest() {
 | 
			
		||||
    $request = $this->getRequest();
 | 
			
		||||
    $user = $request->getUser();
 | 
			
		||||
 | 
			
		||||
    $nav = $this->buildSideNavView();
 | 
			
		||||
 | 
			
		||||
    $issues = PhabricatorSetupCheck::runAllChecks();
 | 
			
		||||
    PhabricatorSetupCheck::setOpenSetupIssueCount(count($issues));
 | 
			
		||||
 | 
			
		||||
    $list = $this->buildIssueList($issues);
 | 
			
		||||
    $list->setNoDataString(pht("There are no open setup issues."));
 | 
			
		||||
 | 
			
		||||
    $header = id(new PhabricatorHeaderView())
 | 
			
		||||
      ->setHeader(pht('Open Phabricator Setup Issues'));
 | 
			
		||||
 | 
			
		||||
    $nav->appendChild(
 | 
			
		||||
      array(
 | 
			
		||||
        $header,
 | 
			
		||||
        $list,
 | 
			
		||||
      ));
 | 
			
		||||
 | 
			
		||||
    $title = pht('Setup Issues');
 | 
			
		||||
 | 
			
		||||
    $crumbs = $this
 | 
			
		||||
      ->buildApplicationCrumbs($nav)
 | 
			
		||||
      ->addCrumb(
 | 
			
		||||
        id(new PhabricatorCrumbView())
 | 
			
		||||
          ->setName($title)
 | 
			
		||||
          ->setHref($this->getApplicationURI('issue/')));
 | 
			
		||||
 | 
			
		||||
    $nav->setCrumbs($crumbs);
 | 
			
		||||
 | 
			
		||||
    return $this->buildApplicationPage(
 | 
			
		||||
      $nav,
 | 
			
		||||
      array(
 | 
			
		||||
        'title' => $title,
 | 
			
		||||
        'device' => true,
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private function buildIssueList(array $issues) {
 | 
			
		||||
    assert_instances_of($issues, 'PhabricatorSetupIssue');
 | 
			
		||||
    $list = new PhabricatorObjectItemListView();
 | 
			
		||||
 | 
			
		||||
    foreach ($issues as $issue) {
 | 
			
		||||
      $href = $this->getApplicationURI('/issue/'.$issue->getIssueKey().'/');
 | 
			
		||||
      $item = id(new PhabricatorObjectItemView())
 | 
			
		||||
        ->setHeader($issue->getName())
 | 
			
		||||
        ->setHref($href)
 | 
			
		||||
        ->setBarColor('yellow')
 | 
			
		||||
        ->addIcon('warning', pht('Setup Warning'))
 | 
			
		||||
        ->addAttribute($issue->getSummary());
 | 
			
		||||
      $list->addItem($item);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $list;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class PhabricatorConfigIssueViewController
 | 
			
		||||
  extends PhabricatorConfigController {
 | 
			
		||||
 | 
			
		||||
  private $issueKey;
 | 
			
		||||
 | 
			
		||||
  public function willProcessRequest(array $data) {
 | 
			
		||||
    $this->issueKey = $data['key'];
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function processRequest() {
 | 
			
		||||
    $request = $this->getRequest();
 | 
			
		||||
    $user = $request->getUser();
 | 
			
		||||
 | 
			
		||||
    $nav = $this->buildSideNavView();
 | 
			
		||||
 | 
			
		||||
    $issues = PhabricatorSetupCheck::runAllChecks();
 | 
			
		||||
    PhabricatorSetupCheck::setOpenSetupIssueCount(count($issues));
 | 
			
		||||
 | 
			
		||||
    if (empty($issues[$this->issueKey])) {
 | 
			
		||||
      $content = id(new AphrontErrorView())
 | 
			
		||||
        ->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
 | 
			
		||||
        ->setTitle(pht('Issue Resolved'))
 | 
			
		||||
        ->appendChild(pht('This setup issue has been resolved. '))
 | 
			
		||||
        ->appendChild(
 | 
			
		||||
          phutil_render_tag(
 | 
			
		||||
            'a',
 | 
			
		||||
            array(
 | 
			
		||||
              'href' => $this->getApplicationURI('issue/'),
 | 
			
		||||
            ),
 | 
			
		||||
            pht('Return to Open Issue List')));
 | 
			
		||||
      $title = pht('Resolved Issue');
 | 
			
		||||
    } else {
 | 
			
		||||
      $issue = $issues[$this->issueKey];
 | 
			
		||||
      $content = $this->renderIssue($issue);
 | 
			
		||||
      $title = $issue->getShortName();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $nav->appendChild($content);
 | 
			
		||||
 | 
			
		||||
    $crumbs = $this
 | 
			
		||||
      ->buildApplicationCrumbs($nav)
 | 
			
		||||
      ->addCrumb(
 | 
			
		||||
        id(new PhabricatorCrumbView())
 | 
			
		||||
          ->setName(pht('Setup Issues'))
 | 
			
		||||
          ->setHref($this->getApplicationURI('issue/')))
 | 
			
		||||
      ->addCrumb(
 | 
			
		||||
        id(new PhabricatorCrumbView())
 | 
			
		||||
          ->setName($title)
 | 
			
		||||
          ->setHref($request->getRequestURI()));
 | 
			
		||||
 | 
			
		||||
    $nav->setCrumbs($crumbs);
 | 
			
		||||
 | 
			
		||||
    return $this->buildApplicationPage(
 | 
			
		||||
      $nav,
 | 
			
		||||
      array(
 | 
			
		||||
        'title' => $title,
 | 
			
		||||
        'device' => true,
 | 
			
		||||
      )
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private function renderIssue(PhabricatorSetupIssue $issue) {
 | 
			
		||||
    require_celerity_resource('setup-issue-css');
 | 
			
		||||
 | 
			
		||||
    $view = new PhabricatorSetupIssueView();
 | 
			
		||||
    $view->setIssue($issue);
 | 
			
		||||
    $view;
 | 
			
		||||
 | 
			
		||||
    $container = phutil_render_tag(
 | 
			
		||||
      'div',
 | 
			
		||||
      array(
 | 
			
		||||
        'class' => 'setup-issue-background',
 | 
			
		||||
      ),
 | 
			
		||||
      $view->render());
 | 
			
		||||
 | 
			
		||||
    return $container;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										113
									
								
								src/applications/config/issue/PhabricatorSetupIssue.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/applications/config/issue/PhabricatorSetupIssue.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class PhabricatorSetupIssue {
 | 
			
		||||
 | 
			
		||||
  private $issueKey;
 | 
			
		||||
  private $name;
 | 
			
		||||
  private $message;
 | 
			
		||||
  private $isFatal;
 | 
			
		||||
  private $summary;
 | 
			
		||||
  private $shortName;
 | 
			
		||||
 | 
			
		||||
  private $phpExtensions = array();
 | 
			
		||||
  private $phabricatorConfig = array();
 | 
			
		||||
  private $phpConfig = array();
 | 
			
		||||
  private $commands = array();
 | 
			
		||||
 | 
			
		||||
  public function addCommand($command) {
 | 
			
		||||
    $this->commands[] = $command;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getCommands() {
 | 
			
		||||
    return $this->commands;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setShortName($short_name) {
 | 
			
		||||
    $this->shortName = $short_name;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getShortName() {
 | 
			
		||||
    if ($this->shortName === null) {
 | 
			
		||||
      return $this->getName();
 | 
			
		||||
    }
 | 
			
		||||
    return $this->shortName;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setName($name) {
 | 
			
		||||
    $this->name = $name;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getName() {
 | 
			
		||||
    return $this->name;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setSummary($summary) {
 | 
			
		||||
    $this->summary = $summary;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getSummary() {
 | 
			
		||||
    if ($this->summary === null) {
 | 
			
		||||
      return $this->getMessage();
 | 
			
		||||
    }
 | 
			
		||||
    return $this->summary;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setIssueKey($issue_key) {
 | 
			
		||||
    $this->issueKey = $issue_key;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getIssueKey() {
 | 
			
		||||
    return $this->issueKey;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setIsFatal($is_fatal) {
 | 
			
		||||
    $this->isFatal = $is_fatal;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getIsFatal() {
 | 
			
		||||
    return $this->isFatal;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function addPHPConfig($php_config) {
 | 
			
		||||
    $this->phpConfig[] = $php_config;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getPHPConfig() {
 | 
			
		||||
    return $this->phpConfig;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function addPhabricatorConfig($phabricator_config) {
 | 
			
		||||
    $this->phabricatorConfig[] = $phabricator_config;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getPhabricatorConfig() {
 | 
			
		||||
    return $this->phabricatorConfig;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function addPHPExtension($php_extension) {
 | 
			
		||||
    $this->phpExtensions[] = $php_extension;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getPHPExtensions() {
 | 
			
		||||
    return $this->phpExtensions;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function setMessage($message) {
 | 
			
		||||
    $this->message = $message;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getMessage() {
 | 
			
		||||
    return $this->message;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										290
									
								
								src/applications/config/view/PhabricatorSetupIssueView.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								src/applications/config/view/PhabricatorSetupIssueView.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,290 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
final class PhabricatorSetupIssueView extends AphrontView {
 | 
			
		||||
 | 
			
		||||
  private $issue;
 | 
			
		||||
 | 
			
		||||
  public function setIssue(PhabricatorSetupIssue $issue) {
 | 
			
		||||
    $this->issue = $issue;
 | 
			
		||||
    return $this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function getIssue() {
 | 
			
		||||
    return $this->issue;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public function render() {
 | 
			
		||||
    $issue = $this->getIssue();
 | 
			
		||||
 | 
			
		||||
    $description = phutil_render_tag(
 | 
			
		||||
      'div',
 | 
			
		||||
      array(
 | 
			
		||||
        'class' => 'setup-issue-instructions',
 | 
			
		||||
      ),
 | 
			
		||||
      nl2br(phutil_escape_html($issue->getMessage())));
 | 
			
		||||
 | 
			
		||||
    $configs = $issue->getPhabricatorConfig();
 | 
			
		||||
    if ($configs) {
 | 
			
		||||
      $description .= $this->renderPhabricatorConfig($configs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $configs = $issue->getPHPConfig();
 | 
			
		||||
    if ($configs) {
 | 
			
		||||
      $description .= $this->renderPHPConfig($configs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $commands = $issue->getCommands();
 | 
			
		||||
    if ($commands) {
 | 
			
		||||
      $run_these = pht("Run these %d command(s):", count($commands));
 | 
			
		||||
      $description .= phutil_render_tag(
 | 
			
		||||
        'div',
 | 
			
		||||
        array(
 | 
			
		||||
          'class' => 'setup-issue-config',
 | 
			
		||||
        ),
 | 
			
		||||
        phutil_render_tag('p', array(), $run_these).
 | 
			
		||||
        phutil_render_tag('pre', array(), implode("\n", $commands)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $extensions = $issue->getPHPExtensions();
 | 
			
		||||
    if ($extensions) {
 | 
			
		||||
      $install_these = pht(
 | 
			
		||||
        "Install these %d PHP extension(s):", count($extensions));
 | 
			
		||||
 | 
			
		||||
      $install_info = pht(
 | 
			
		||||
        "You can usually install a PHP extension using <tt>apt-get</tt> or ".
 | 
			
		||||
        "<tt>yum</tt>. Common package names are ".
 | 
			
		||||
        "<tt>php-<em>extname</em></tt> or <tt>php5-<em>extname</em></tt>. ".
 | 
			
		||||
        "Try commands like these:");
 | 
			
		||||
 | 
			
		||||
      // TODO: We should do a better job of detecting how to install extensions
 | 
			
		||||
      // on the current system.
 | 
			
		||||
      $install_commands = array(
 | 
			
		||||
        "$ sudo apt-get install php5-<em>extname</em>  # Debian / Ubuntu",
 | 
			
		||||
        "$ sudo yum install php5-<em>extname</em>      # Red Hat / Derivatives",
 | 
			
		||||
      );
 | 
			
		||||
      $install_commands = implode("\n", $install_commands);
 | 
			
		||||
 | 
			
		||||
      $fallback_info = pht(
 | 
			
		||||
        "If those commands don't work, try Google. The process of installing ".
 | 
			
		||||
        "PHP extensions is not specific to Phabricator, and any instructions ".
 | 
			
		||||
        "you can find for installing them on your system should work. On Mac ".
 | 
			
		||||
        "OS X, you might want to try Homebrew.");
 | 
			
		||||
 | 
			
		||||
      $restart_info = pht(
 | 
			
		||||
        "After installing new PHP extensions, <strong>restart your webserver ".
 | 
			
		||||
        "for the changes to take effect</strong>.");
 | 
			
		||||
 | 
			
		||||
      $description .= phutil_render_tag(
 | 
			
		||||
        'div',
 | 
			
		||||
        array(
 | 
			
		||||
          'class' => 'setup-issue-config',
 | 
			
		||||
        ),
 | 
			
		||||
        phutil_render_tag('p', array(), $install_these).
 | 
			
		||||
        phutil_render_tag('pre', array(), implode("\n", $extensions)).
 | 
			
		||||
        phutil_render_tag('p', array(), $install_info).
 | 
			
		||||
        phutil_render_tag('pre', array(), $install_commands).
 | 
			
		||||
        phutil_render_tag('p', array(), $fallback_info).
 | 
			
		||||
        phutil_render_tag('p', array(), $restart_info));
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $next = phutil_render_tag(
 | 
			
		||||
      'div',
 | 
			
		||||
      array(
 | 
			
		||||
        'class' => 'setup-issue-next',
 | 
			
		||||
      ),
 | 
			
		||||
      pht('To continue, resolve this problem and reload the page.'));
 | 
			
		||||
 | 
			
		||||
    $name = phutil_render_tag(
 | 
			
		||||
      'div',
 | 
			
		||||
      array(
 | 
			
		||||
        'class' => 'setup-issue-name',
 | 
			
		||||
      ),
 | 
			
		||||
      phutil_escape_html($issue->getName()));
 | 
			
		||||
 | 
			
		||||
    return phutil_render_tag(
 | 
			
		||||
      'div',
 | 
			
		||||
      array(
 | 
			
		||||
        'class' => 'setup-issue',
 | 
			
		||||
      ),
 | 
			
		||||
      $name.$description.$next);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private function renderPhabricatorConfig(array $configs) {
 | 
			
		||||
    $table_info = phutil_render_tag(
 | 
			
		||||
      'p',
 | 
			
		||||
      array(),
 | 
			
		||||
      pht(
 | 
			
		||||
        "The current Phabricator configuration has these %d value(s):",
 | 
			
		||||
        count($configs)));
 | 
			
		||||
 | 
			
		||||
    $table = array();
 | 
			
		||||
    foreach ($configs as $key) {
 | 
			
		||||
      $table[] = '<tr>';
 | 
			
		||||
      $table[] = '<th>'.phutil_escape_html($key).'</th>';
 | 
			
		||||
 | 
			
		||||
      $value = PhabricatorEnv::getEnvConfig($key);
 | 
			
		||||
      if ($value === null) {
 | 
			
		||||
        $value = '<em>null</em>';
 | 
			
		||||
      } else if ($value === false) {
 | 
			
		||||
        $value = '<em>false</em>';
 | 
			
		||||
      } else if ($value === true) {
 | 
			
		||||
        $value = '<em>true</em>';
 | 
			
		||||
      } else {
 | 
			
		||||
        $value = phutil_escape_html($value);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $table[] = '<td>'.$value.'</td>';
 | 
			
		||||
      $table[] = '</tr>';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $table = phutil_render_tag(
 | 
			
		||||
      'table',
 | 
			
		||||
      array(
 | 
			
		||||
 | 
			
		||||
      ),
 | 
			
		||||
      implode("\n", $table));
 | 
			
		||||
 | 
			
		||||
    $update_info = phutil_render_tag(
 | 
			
		||||
      'p',
 | 
			
		||||
      array(),
 | 
			
		||||
      pht(
 | 
			
		||||
        "To update these %d value(s), run these command(s) from the command ".
 | 
			
		||||
        "line:",
 | 
			
		||||
        count($configs)));
 | 
			
		||||
 | 
			
		||||
    $update = array();
 | 
			
		||||
    foreach ($configs as $key) {
 | 
			
		||||
      $cmd = '<tt>phabricator/ $</tt> ./bin/config set '.
 | 
			
		||||
              phutil_escape_html($key).' '.
 | 
			
		||||
             '<em>value</em>';
 | 
			
		||||
      $update[] = $cmd;
 | 
			
		||||
    }
 | 
			
		||||
    $update = phutil_render_tag('pre', array(), implode("\n", $update));
 | 
			
		||||
 | 
			
		||||
    return phutil_render_tag(
 | 
			
		||||
      'div',
 | 
			
		||||
      array(
 | 
			
		||||
        'class' => 'setup-issue-config',
 | 
			
		||||
      ),
 | 
			
		||||
      self::renderSingleView(
 | 
			
		||||
        array(
 | 
			
		||||
          $table_info,
 | 
			
		||||
          $table,
 | 
			
		||||
          $update_info,
 | 
			
		||||
          $update,
 | 
			
		||||
        )));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private function renderPHPConfig(array $configs) {
 | 
			
		||||
    $table_info = phutil_render_tag(
 | 
			
		||||
      'p',
 | 
			
		||||
      array(),
 | 
			
		||||
      pht(
 | 
			
		||||
        "The current PHP configuration has these %d value(s):",
 | 
			
		||||
        count($configs)));
 | 
			
		||||
 | 
			
		||||
    $table = array();
 | 
			
		||||
    foreach ($configs as $key) {
 | 
			
		||||
      $table[] = '<tr>';
 | 
			
		||||
      $table[] = '<th>'.phutil_escape_html($key).'</th>';
 | 
			
		||||
 | 
			
		||||
      $value = ini_get($key);
 | 
			
		||||
      if ($value === null) {
 | 
			
		||||
        $value = '<em>null</em>';
 | 
			
		||||
      } else if ($value === false) {
 | 
			
		||||
        $value = '<em>false</em>';
 | 
			
		||||
      } else if ($value === true) {
 | 
			
		||||
        $value = '<em>true</em>';
 | 
			
		||||
      } else if ($value === '') {
 | 
			
		||||
        $value = '<em>(empty string)</em>';
 | 
			
		||||
      } else {
 | 
			
		||||
        $value = phutil_escape_html($value);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      $table[] = '<td>'.$value.'</td>';
 | 
			
		||||
      $table[] = '</tr>';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $table = phutil_render_tag(
 | 
			
		||||
      'table',
 | 
			
		||||
      array(
 | 
			
		||||
 | 
			
		||||
      ),
 | 
			
		||||
      implode("\n", $table));
 | 
			
		||||
 | 
			
		||||
    ob_start();
 | 
			
		||||
      phpinfo();
 | 
			
		||||
    $phpinfo = ob_get_clean();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    $rex = '@Loaded Configuration File\s*</td><td class="v">(.*?)</td>@i';
 | 
			
		||||
    $matches = null;
 | 
			
		||||
 | 
			
		||||
    $ini_loc = null;
 | 
			
		||||
    if (preg_match($rex, $phpinfo, $matches)) {
 | 
			
		||||
      $ini_loc = trim($matches[1]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $rex = '@Additional \.ini files parsed\s*</td><td class="v">(.*?)</td>@i';
 | 
			
		||||
 | 
			
		||||
    $more_loc = array();
 | 
			
		||||
    if (preg_match($rex, $phpinfo, $matches)) {
 | 
			
		||||
      $more_loc = trim($matches[1]);
 | 
			
		||||
      if ($more_loc == '(none)') {
 | 
			
		||||
        $more_loc = array();
 | 
			
		||||
      } else {
 | 
			
		||||
        $more_loc = preg_split('/\s*,\s*/', $more_loc);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!$ini_loc) {
 | 
			
		||||
      $info = phutil_render_tag(
 | 
			
		||||
        'p',
 | 
			
		||||
        array(),
 | 
			
		||||
        pht(
 | 
			
		||||
          "To update these %d value(s), edit your PHP configuration file.",
 | 
			
		||||
          count($configs)));
 | 
			
		||||
    } else {
 | 
			
		||||
      $info = phutil_render_tag(
 | 
			
		||||
        'p',
 | 
			
		||||
        array(),
 | 
			
		||||
        pht(
 | 
			
		||||
          "To update these %d value(s), edit your PHP configuration file, ".
 | 
			
		||||
          "located here:",
 | 
			
		||||
          count($configs)));
 | 
			
		||||
      $info .= phutil_render_tag(
 | 
			
		||||
        'pre',
 | 
			
		||||
        array(),
 | 
			
		||||
        phutil_escape_html($ini_loc));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($more_loc) {
 | 
			
		||||
      $info .= phutil_render_tag(
 | 
			
		||||
        'p',
 | 
			
		||||
        array(),
 | 
			
		||||
        pht(
 | 
			
		||||
          "PHP also loaded these configuration file(s):",
 | 
			
		||||
          count($more_loc)));
 | 
			
		||||
      $info .= phutil_render_tag(
 | 
			
		||||
        'pre',
 | 
			
		||||
        array(),
 | 
			
		||||
        phutil_escape_html(implode("\n", $more_loc)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $info .= phutil_render_tag(
 | 
			
		||||
      'p',
 | 
			
		||||
      array(),
 | 
			
		||||
      pht(
 | 
			
		||||
        "After editing the PHP configuration, <strong>restart your webserver ".
 | 
			
		||||
        "for the changes to take effect</strong>."));
 | 
			
		||||
 | 
			
		||||
    return phutil_render_tag(
 | 
			
		||||
      'div',
 | 
			
		||||
      array(
 | 
			
		||||
        'class' => 'setup-issue-config',
 | 
			
		||||
      ),
 | 
			
		||||
      $table_info.$table.$info);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -38,6 +38,8 @@ try {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  PhabricatorSetupCheck::willProcessRequest();
 | 
			
		||||
 | 
			
		||||
  phabricator_detect_bad_base_uri();
 | 
			
		||||
 | 
			
		||||
  $host = $_SERVER['HTTP_HOST'];
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										86
									
								
								webroot/rsrc/css/application/config/setup-issue.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								webroot/rsrc/css/application/config/setup-issue.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @provides setup-issue-css
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.setup-issue-background {
 | 
			
		||||
  background-color: #edecef;
 | 
			
		||||
  padding: 1em 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue {
 | 
			
		||||
  border: 1px solid #35393d;
 | 
			
		||||
  margin: 15px auto;
 | 
			
		||||
  max-width: 760px;
 | 
			
		||||
  background: #ffffff;
 | 
			
		||||
  box-shadow: 1px 2px 2px rgba(0, 0, 0, 0.25);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue p {
 | 
			
		||||
  margin: 1em 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue table {
 | 
			
		||||
  width: 90%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
  border-collapse: collapse;
 | 
			
		||||
  border: 1px solid #dfdfdf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue table th {
 | 
			
		||||
  text-align: right;
 | 
			
		||||
  width: 30%;
 | 
			
		||||
  background: #efefef;
 | 
			
		||||
  border: 1px solid #dfdfdf;
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue table td {
 | 
			
		||||
  border: 1px solid #dfdfdf;
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue pre {
 | 
			
		||||
  width: 84%;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
  border: 1px solid #dfdfdf;
 | 
			
		||||
  padding: 10px 3%;
 | 
			
		||||
  background: #efefef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue tt {
 | 
			
		||||
  color: #666666;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue em {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue-instructions {
 | 
			
		||||
  font-size: 15px;
 | 
			
		||||
  padding: 20px;
 | 
			
		||||
  line-height: 1.4em;
 | 
			
		||||
  background: #efefef;
 | 
			
		||||
  border-bottom: 1px solid #bfbfbf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue-name {
 | 
			
		||||
  padding: 15px;
 | 
			
		||||
  background: #35393d;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
  font-size: 15px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue-next {
 | 
			
		||||
  padding: 15px;
 | 
			
		||||
  background: #35393d;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.setup-issue-config {
 | 
			
		||||
  margin: 15px 0;
 | 
			
		||||
  padding: 0 20px;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user