public static function getJumpResponse(PhabricatorUser $viewer, $jump)
 {
     $jump = trim($jump);
     $help_href = PhabricatorEnv::getDocLink('Jump Nav User Guide');
     $patterns = array('/^help/i' => 'uri:' . $help_href, '/^a$/i' => 'uri:/audit/', '/^f$/i' => 'uri:/feed/', '/^d$/i' => 'uri:/differential/', '/^r$/i' => 'uri:/diffusion/', '/^t$/i' => 'uri:/maniphest/', '/^p$/i' => 'uri:/project/', '/^u$/i' => 'uri:/people/', '/^p\\s+(.+)$/i' => 'project', '/^u\\s+(\\S+)$/i' => 'user', '/^task:\\s*(.+)/i' => 'create-task', '/^(?:s|symbol)\\s+(\\S+)/i' => 'find-symbol', '/^r\\s+(.+)$/i' => 'find-repository');
     foreach ($patterns as $pattern => $effect) {
         $matches = null;
         if (preg_match($pattern, $jump, $matches)) {
             if (!strncmp($effect, 'uri:', 4)) {
                 return id(new AphrontRedirectResponse())->setURI(substr($effect, 4));
             } else {
                 switch ($effect) {
                     case 'user':
                         return id(new AphrontRedirectResponse())->setURI('/p/' . $matches[1] . '/');
                     case 'project':
                         $project = self::findCloselyNamedProject($matches[1]);
                         if ($project) {
                             return id(new AphrontRedirectResponse())->setURI('/project/view/' . $project->getID() . '/');
                         } else {
                             $jump = $matches[1];
                         }
                         break;
                     case 'find-symbol':
                         $context = '';
                         $symbol = $matches[1];
                         $parts = array();
                         if (preg_match('/(.*)(?:\\.|::|->)(.*)/', $symbol, $parts)) {
                             $context = '&context=' . phutil_escape_uri($parts[1]);
                             $symbol = $parts[2];
                         }
                         return id(new AphrontRedirectResponse())->setURI("/diffusion/symbol/{$symbol}/?jump=true{$context}");
                     case 'find-repository':
                         $name = $matches[1];
                         $repositories = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withNameContains($name)->execute();
                         if (count($repositories) == 1) {
                             // Just one match, jump to repository.
                             $uri = '/diffusion/' . head($repositories)->getCallsign() . '/';
                         } else {
                             // More than one match, jump to search.
                             $uri = urisprintf('/diffusion/?order=name&name=%s', $name);
                         }
                         return id(new AphrontRedirectResponse())->setURI($uri);
                     case 'create-task':
                         return id(new AphrontRedirectResponse())->setURI('/maniphest/task/create/?title=' . phutil_escape_uri($matches[1]));
                     default:
                         throw new Exception("Unknown jump effect '{$effect}'!");
                 }
             }
         }
     }
     // If none of the patterns matched, look for an object by name.
     $objects = id(new PhabricatorObjectQuery())->setViewer($viewer)->withNames(array($jump))->execute();
     if (count($objects) == 1) {
         $handle = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(mpull($objects, 'getPHID'))->executeOne();
         return id(new AphrontRedirectResponse())->setURI($handle->getURI());
     }
     return null;
 }
 public static function renderUploadLimit()
 {
     $limit = PhabricatorEnv::getEnvConfig('storage.upload-size-limit');
     $limit = phabricator_parse_bytes($limit);
     if ($limit) {
         $formatted = phabricator_format_bytes($limit);
         return 'Maximum file size: ' . phutil_escape_html($formatted);
     }
     $doc_href = PhabricatorEnv::getDocLink('article/Configuring_File_Upload_Limits.html');
     $doc_link = phutil_render_tag('a', array('href' => $doc_href, 'target' => '_blank'), 'Configuring File Upload Limits');
     return 'Upload limit is not configured, see ' . $doc_link . '.';
 }
 private function renderUploadLimit()
 {
     $limit = PhabricatorEnv::getEnvConfig('storage.upload-size-limit');
     $limit = phutil_parse_bytes($limit);
     if ($limit) {
         $formatted = phutil_format_bytes($limit);
         return 'Maximum file size: ' . $formatted;
     }
     $doc_href = PhabricatorEnv::getDocLink('Configuring File Upload Limits');
     $doc_link = phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), 'Configuring File Upload Limits');
     return hsprintf('Upload limit is not configured, see %s.', $doc_link);
 }
 public static function jumpPostResponse($jump)
 {
     $jump = trim($jump);
     $help_href = PhabricatorEnv::getDocLink('article/Jump_Nav_User_Guide.html');
     $patterns = array('/^help/i' => 'uri:' . $help_href, '/^a$/i' => 'uri:/audit/', '/^f$/i' => 'uri:/feed/', '/^d$/i' => 'uri:/differential/', '/^r$/i' => 'uri:/diffusion/', '/^t$/i' => 'uri:/maniphest/', '/^p$/i' => 'uri:/project/', '/^u$/i' => 'uri:/people/', '/^r([A-Z]+)$/' => 'repository', '/^r([A-Z]+)(\\S+)$/' => 'commit', '/^d(\\d+)$/i' => 'revision', '/^t(\\d+)$/i' => 'task', '/^p\\s+(.+)$/i' => 'project', '/^u\\s+(\\S+)$/i' => 'user', '/^task:\\s*(.+)/i' => 'create-task', '/^(?:s|symbol)\\s+(\\S+)/i' => 'find-symbol');
     foreach ($patterns as $pattern => $effect) {
         $matches = null;
         if (preg_match($pattern, $jump, $matches)) {
             if (!strncmp($effect, 'uri:', 4)) {
                 return id(new AphrontRedirectResponse())->setURI(substr($effect, 4));
             } else {
                 switch ($effect) {
                     case 'repository':
                         return id(new AphrontRedirectResponse())->setURI('/diffusion/' . $matches[1] . '/');
                     case 'commit':
                         return id(new AphrontRedirectResponse())->setURI('/' . $matches[0]);
                     case 'revision':
                         return id(new AphrontRedirectResponse())->setURI('/D' . $matches[1]);
                     case 'task':
                         return id(new AphrontRedirectResponse())->setURI('/T' . $matches[1]);
                     case 'user':
                         return id(new AphrontRedirectResponse())->setURI('/p/' . $matches[1] . '/');
                     case 'project':
                         $project = self::findCloselyNamedProject($matches[1]);
                         if ($project) {
                             return id(new AphrontRedirectResponse())->setURI('/project/view/' . $project->getID() . '/');
                         } else {
                             $jump = $matches[1];
                         }
                         break;
                     case 'find-symbol':
                         $context = '';
                         $symbol = $matches[1];
                         $parts = array();
                         if (preg_match('/(.*)(?:\\.|::|->)(.*)/', $symbol, $parts)) {
                             $context = '&context=' . phutil_escape_uri($parts[1]);
                             $symbol = $parts[2];
                         }
                         return id(new AphrontRedirectResponse())->setURI("/diffusion/symbol/{$symbol}/?jump=true{$context}");
                     case 'create-task':
                         return id(new AphrontRedirectResponse())->setURI('/maniphest/task/create/?title=' . phutil_escape_uri($matches[1]));
                     default:
                         throw new Exception("Unknown jump effect '{$effect}'!");
                 }
             }
         }
     }
     return null;
 }
 protected function executeChecks()
 {
     if (empty($_SERVER['REMOTE_ADDR'])) {
         $doc_href = PhabricatorEnv::getDocLink('Configuring a Preamble Script');
         $summary = pht('You likely need to fix your preamble script so ' . 'REMOTE_ADDR is no longer empty.');
         $message = pht('No REMOTE_ADDR is available, so Phabricator cannot determine the ' . 'origin address for requests. This will prevent Phabricator from ' . 'performing important security checks. This most often means you ' . 'have a mistake in your preamble script. Consult the documentation ' . '(%s) and double-check that the script is written correctly.', phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Configuring a Preamble Script')));
         $this->newIssue('php.remote_addr')->setName(pht('No REMOTE_ADDR available'))->setSummary($summary)->setMessage($message);
     }
     $raw_post_data = (int) ini_get('always_populate_raw_post_data');
     if ($raw_post_data != -1) {
         $summary = pht('PHP setting "%s" should be set to "-1" to avoid deprecation ' . 'warnings.', 'always_populate_raw_post_data');
         $message = pht('The "%s" key is set to some value other than "-1" in your PHP ' . 'configuration. This can cause PHP to raise deprecation warnings ' . 'during process startup. Set this option to "-1" to prevent these ' . 'warnings from appearing.', 'always_populate_raw_post_data');
         $this->newIssue('php.always_populate_raw_post_data')->setName(pht('Disable PHP %s', 'always_populate_raw_post_data'))->setSummary($summary)->setMessage($message)->addPHPConfig('always_populate_raw_post_data');
     }
 }
 /**
  * @phutil-external-symbol class PhabricatorStartup
  */
 protected function executeChecks()
 {
     $engines = PhabricatorFileStorageEngine::loadWritableChunkEngines();
     $chunk_engine_active = (bool) $engines;
     $this->checkS3();
     if (!$chunk_engine_active) {
         $doc_href = PhabricatorEnv::getDocLink('Configuring File Storage');
         $message = pht('Large file storage has not been configured, which will limit ' . 'the maximum size of file uploads. See %s for ' . 'instructions on configuring uploads and storage.', phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Configuring File Storage')));
         $this->newIssue('large-files')->setShortName(pht('Large Files'))->setName(pht('Large File Storage Not Configured'))->setMessage($message);
     }
     $post_max_size = ini_get('post_max_size');
     if ($post_max_size && (int) $post_max_size > 0) {
         $post_max_bytes = phutil_parse_bytes($post_max_size);
         $post_max_need = 32 * 1024 * 1024;
         if ($post_max_need > $post_max_bytes) {
             $summary = pht('Set %s in your PHP configuration to at least 32MB ' . 'to support large file uploads.', phutil_tag('tt', array(), 'post_max_size'));
             $message = pht('Adjust %s in your PHP configuration to at least 32MB. When ' . 'set to smaller value, large file uploads may not work properly.', phutil_tag('tt', array(), 'post_max_size'));
             $this->newIssue('php.post_max_size')->setName(pht('PHP post_max_size Not Configured'))->setSummary($summary)->setMessage($message)->setGroup(self::GROUP_PHP)->addPHPConfig('post_max_size');
         }
     }
     // This is somewhat arbitrary, but make sure we have enough headroom to
     // upload a default file at the chunk threshold (8MB), which may be
     // base64 encoded, then JSON encoded in the request, and may need to be
     // held in memory in the raw and as a query string.
     $need_bytes = 64 * 1024 * 1024;
     $memory_limit = PhabricatorStartup::getOldMemoryLimit();
     if ($memory_limit && (int) $memory_limit > 0) {
         $memory_limit_bytes = phutil_parse_bytes($memory_limit);
         $memory_usage_bytes = memory_get_usage();
         $available_bytes = $memory_limit_bytes - $memory_usage_bytes;
         if ($need_bytes > $available_bytes) {
             $summary = pht('Your PHP memory limit is configured in a way that may prevent ' . 'you from uploading large files or handling large requests.');
             $message = pht('When you upload a file via drag-and-drop or the API, chunks must ' . 'be buffered into memory before being written to permanent ' . 'storage. Phabricator needs memory available to store these ' . 'chunks while they are uploaded, but PHP is currently configured ' . 'to severly limit the available memory.' . "\n\n" . 'PHP processes currently have very little free memory available ' . '(%s). To work well, processes should have at least %s.' . "\n\n" . '(Note that the application itself must also fit in available ' . 'memory, so not all of the memory under the memory limit is ' . 'available for running workloads.)' . "\n\n" . "The easiest way to resolve this issue is to set %s to %s in your " . "PHP configuration, to disable the memory limit. There is " . "usually little or no value to using this option to limit " . "Phabricator process memory." . "\n\n" . "You can also increase the limit or ignore this issue and accept " . "that you may encounter problems uploading large files and " . "processing large requests.", phutil_format_bytes($available_bytes), phutil_format_bytes($need_bytes), phutil_tag('tt', array(), 'memory_limit'), phutil_tag('tt', array(), '-1'));
             $this->newIssue('php.memory_limit.upload')->setName(pht('Memory Limit Restricts File Uploads'))->setSummary($summary)->setMessage($message)->setGroup(self::GROUP_PHP)->addPHPConfig('memory_limit')->addPHPConfigOriginalValue('memory_limit', $memory_limit);
         }
     }
     $local_path = PhabricatorEnv::getEnvConfig('storage.local-disk.path');
     if (!$local_path) {
         return;
     }
     if (!Filesystem::pathExists($local_path) || !is_readable($local_path) || !is_writable($local_path)) {
         $message = pht('Configured location for storing uploaded files on disk ("%s") does ' . 'not exist, or is not readable or writable. Verify the directory ' . 'exists and is readable and writable by the webserver.', $local_path);
         $this->newIssue('config.storage.local-disk.path')->setShortName(pht('Local Disk Storage'))->setName(pht('Local Disk Storage Not Readable/Writable'))->setMessage($message)->addPhabricatorConfig('storage.local-disk.path');
     }
 }
 protected function executeChecks()
 {
     // This checks for a version of bash with the "Shellshock" vulnerability.
     // For details, see T6185.
     $payload = array('SHELLSHOCK_PAYLOAD' => '() { :;} ; echo VULNERABLE');
     list($err, $stdout) = id(new ExecFuture('echo shellshock-test'))->setEnv($payload, $wipe_process_env = true)->resolve();
     if (!$err && preg_match('/VULNERABLE/', $stdout)) {
         $summary = pht('This system has an unpatched version of Bash with a severe, widely ' . 'disclosed vulnerability.');
         $message = pht('The version of %s on this system is out of date and contains a ' . 'major, widely disclosed vulnerability (the "Shellshock" ' . 'vulnerability).' . "\n\n" . 'Upgrade %s to a patched version.' . "\n\n" . 'To learn more about how this issue affects Phabricator, see %s.', phutil_tag('tt', array(), 'bash'), phutil_tag('tt', array(), 'bash'), phutil_tag('a', array('href' => 'https://secure.phabricator.com/T6185', 'target' => '_blank'), pht('T6185 "Shellshock" Bash Vulnerability')));
         $this->newIssue('security.shellshock')->setName(pht('Severe Security Vulnerability: Unpatched Bash'))->setSummary($summary)->setMessage($message);
     }
     $file_key = 'security.alternate-file-domain';
     $file_domain = PhabricatorEnv::getEnvConfig($file_key);
     if (!$file_domain) {
         $doc_href = PhabricatorEnv::getDocLink('Configuring a File Domain');
         $this->newIssue('security.' . $file_key)->setName(pht('Alternate File Domain Not Configured'))->setSummary(pht('Increase security (and improve performance) by configuring ' . 'a CDN or alternate file domain.'))->setMessage(pht('Phabricator is currently configured to serve user uploads ' . 'directly from the same domain as other content. This is a ' . 'security risk.' . "\n\n" . 'Configure a CDN (or alternate file domain) to eliminate this ' . 'risk. Using a CDN will also improve performance. See the ' . 'guide below for instructions.'))->addPhabricatorConfig($file_key)->addLink($doc_href, pht('Configuration Guide: Configuring a File Domain'));
     }
 }
 protected function executeChecks()
 {
     $task_daemon = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_RUNNING)->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))->setLimit(1)->execute();
     if (!$task_daemon) {
         $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
         $summary = pht('You must start the Phabricator daemons to send email, rebuild ' . 'search indexes, and do other background processing.');
         $message = pht('The Phabricator daemons are not running, so Phabricator will not ' . 'be able to perform background processing (including sending email, ' . 'rebuilding search indexes, importing commits, cleaning up old data, ' . 'and running builds).' . "\n\n" . 'Use %s to start daemons. See %s for more information.', phutil_tag('tt', array(), 'bin/phd start'), phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Managing Daemons with phd')));
         $this->newIssue('daemons.not-running')->setShortName(pht('Daemons Not Running'))->setName(pht('Phabricator Daemons Are Not Running'))->setSummary($summary)->setMessage($message)->addCommand('phabricator/ $ ./bin/phd start');
     }
     $phd_user = PhabricatorEnv::getEnvConfig('phd.user');
     $environment_hash = PhabricatorEnv::calculateEnvironmentHash();
     $all_daemons = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)->execute();
     foreach ($all_daemons as $daemon) {
         if ($phd_user) {
             if ($daemon->getRunningAsUser() != $phd_user) {
                 $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
                 $summary = pht('At least one daemon is currently running as a different ' . 'user than configured in the Phabricator %s setting', 'phd.user');
                 $message = pht('A daemon is running as user %s while the Phabricator config ' . 'specifies %s to be %s.' . "\n\n" . 'Either adjust %s to match %s or start ' . 'the daemons as the correct user. ' . "\n\n" . '%s Daemons will try to use %s to start as the configured user. ' . 'Make sure that the user who starts %s has the correct ' . 'sudo permissions to start %s daemons as %s', 'phd.user', 'phd.user', 'phd', 'sudo', 'phd', 'phd', phutil_tag('tt', array(), $daemon->getRunningAsUser()), phutil_tag('tt', array(), $phd_user), phutil_tag('tt', array(), $daemon->getRunningAsUser()), phutil_tag('tt', array(), $phd_user));
                 $this->newIssue('daemons.run-as-different-user')->setName(pht('Daemons are running as the wrong user'))->setSummary($summary)->setMessage($message)->addCommand('phabricator/ $ ./bin/phd restart');
             }
         }
         if ($daemon->getEnvHash() != $environment_hash) {
             $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
             $summary = pht('At least one daemon is currently running with different ' . 'configuration than the Phabricator web application.');
             $list_section = null;
             $env_info = $daemon->getEnvInfo();
             if ($env_info) {
                 $issues = PhabricatorEnv::compareEnvironmentInfo(PhabricatorEnv::calculateEnvironmentInfo(), $env_info);
                 if ($issues) {
                     foreach ($issues as $key => $issue) {
                         $issues[$key] = phutil_tag('li', array(), $issue);
                     }
                     $list_section = array(pht('The configurations differ in the following %s way(s):', phutil_count($issues)), phutil_tag('ul', array(), $issues));
                 }
             }
             $message = pht('At least one daemon is currently running with a different ' . 'configuration (config checksum %s) than the web application ' . '(config checksum %s).' . "\n\n%s" . 'This usually means that you have just made a configuration change ' . 'from the web UI, but have not yet restarted the daemons. You ' . 'need to restart the daemons after making configuration changes ' . 'so they will pick up the new values: until you do, they will ' . 'continue operating with the old settings.' . "\n\n" . '(If you plan to make more changes, you can restart the daemons ' . 'once after you finish making all of your changes.)' . "\n\n" . 'Use %s to restart daemons. You can find a list of running daemons ' . 'in the %s, which will also help you identify which daemon (or ' . 'daemons) have divergent configuration. For more information about ' . 'managing the daemons, see %s in the documentation.' . "\n\n" . 'This can also happen if you use the %s environmental variable to ' . 'choose a configuration file, but the daemons run with a different ' . 'value than the web application. If restarting the daemons does ' . 'not resolve this issue and you use %s to select configuration, ' . 'check that it is set consistently.' . "\n\n" . 'A third possible cause is that you run several machines, and ' . 'the %s configuration file differs between them. This file is ' . 'updated when you edit configuration from the CLI with %s. If ' . 'restarting the daemons does not resolve this issue and you ' . 'run multiple machines, check that all machines have identical ' . '%s configuration files.' . "\n\n" . 'This issue is not severe, but usually indicates that something ' . 'is not configured the way you expect, and may cause the daemons ' . 'to exhibit different behavior than the web application does.', phutil_tag('tt', array(), substr($daemon->getEnvHash(), 0, 12)), phutil_tag('tt', array(), substr($environment_hash, 0, 12)), $list_section, phutil_tag('tt', array(), 'bin/phd restart'), phutil_tag('a', array('href' => '/daemon/', 'target' => '_blank'), pht('Daemon Console')), phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Managing Daemons with phd')), phutil_tag('tt', array(), 'PHABRICATOR_ENV'), phutil_tag('tt', array(), 'PHABRICATOR_ENV'), phutil_tag('tt', array(), 'phabricator/conf/local/local.json'), phutil_tag('tt', array(), 'bin/config'), phutil_tag('tt', array(), 'phabricator/conf/local/local.json'));
             $this->newIssue('daemons.need-restarting')->setName(pht('Daemons and Web Have Different Config'))->setSummary($summary)->setMessage($message)->addCommand('phabricator/ $ ./bin/phd restart');
             break;
         }
     }
 }
 protected function executeChecks()
 {
     $task_daemon = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_RUNNING)->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))->setLimit(1)->execute();
     if (!$task_daemon) {
         $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
         $summary = pht('You must start the Phabricator daemons to send email, rebuild ' . 'search indexes, and do other background processing.');
         $message = pht('The Phabricator daemons are not running, so Phabricator will not ' . 'be able to perform background processing (including sending email, ' . 'rebuilding search indexes, importing commits, cleaning up old data, ' . 'and running builds).' . "\n\n" . 'Use %s to start daemons. See %s for more information.', phutil_tag('tt', array(), 'bin/phd start'), phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Managing Daemons with phd')));
         $this->newIssue('daemons.not-running')->setShortName(pht('Daemons Not Running'))->setName(pht('Phabricator Daemons Are Not Running'))->setSummary($summary)->setMessage($message)->addCommand('phabricator/ $ ./bin/phd start');
     }
     $phd_user = PhabricatorEnv::getEnvConfig('phd.user');
     $all_daemons = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)->execute();
     foreach ($all_daemons as $daemon) {
         if ($phd_user) {
             if ($daemon->getRunningAsUser() != $phd_user) {
                 $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
                 $summary = pht('At least one daemon is currently running as a different ' . 'user than configured in the Phabricator %s setting', 'phd.user');
                 $message = pht('A daemon is running as user %s while the Phabricator config ' . 'specifies %s to be %s.' . "\n\n" . 'Either adjust %s to match %s or start ' . 'the daemons as the correct user. ' . "\n\n" . '%s Daemons will try to use %s to start as the configured user. ' . 'Make sure that the user who starts %s has the correct ' . 'sudo permissions to start %s daemons as %s', 'phd.user', 'phd.user', 'phd', 'sudo', 'phd', 'phd', phutil_tag('tt', array(), $daemon->getRunningAsUser()), phutil_tag('tt', array(), $phd_user), phutil_tag('tt', array(), $daemon->getRunningAsUser()), phutil_tag('tt', array(), $phd_user));
                 $this->newIssue('daemons.run-as-different-user')->setName(pht('Daemons are running as the wrong user'))->setSummary($summary)->setMessage($message)->addCommand('phabricator/ $ ./bin/phd restart');
             }
         }
     }
 }
 protected function executeChecks()
 {
     $task_daemon = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_RUNNING)->withDaemonClasses(array('PhabricatorTaskmasterDaemon'))->setLimit(1)->execute();
     if (!$task_daemon) {
         $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
         $summary = pht('You must start the Phabricator daemons to send email, rebuild ' . 'search indexes, and do other background processing.');
         $message = pht('The Phabricator daemons are not running, so Phabricator will not ' . 'be able to perform background processing (including sending email, ' . 'rebuilding search indexes, importing commits, cleaning up old data, ' . 'and running builds).' . "\n\n" . 'Use %s to start daemons. See %s for more information.', phutil_tag('tt', array(), 'bin/phd start'), phutil_tag('a', array('href' => $doc_href, 'target' => '_blank'), pht('Managing Daemons with phd')));
         $this->newIssue('daemons.not-running')->setShortName(pht('Daemons Not Running'))->setName(pht('Phabricator Daemons Are Not Running'))->setSummary($summary)->setMessage($message)->addCommand('phabricator/ $ ./bin/phd start');
     }
     $expect_user = PhabricatorEnv::getEnvConfig('phd.user');
     if (strlen($expect_user)) {
         $all_daemons = id(new PhabricatorDaemonLogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withStatus(PhabricatorDaemonLogQuery::STATUS_ALIVE)->execute();
         foreach ($all_daemons as $daemon) {
             $actual_user = $daemon->getRunningAsUser();
             if ($actual_user == $expect_user) {
                 continue;
             }
             $summary = pht('At least one daemon is currently running as the wrong user.');
             $message = pht('A daemon is running as user %s, but daemons should be ' . 'running as %s.' . "\n\n" . 'Either adjust the configuration setting %s or restart the ' . 'daemons. Daemons should attempt to run as the proper user when ' . 'restarted.', phutil_tag('tt', array(), $actual_user), phutil_tag('tt', array(), $expect_user), phutil_tag('tt', array(), 'phd.user'));
             $this->newIssue('daemons.run-as-different-user')->setName(pht('Daemon Running as Wrong User'))->setSummary($summary)->setMessage($message)->addPhabricatorConfig('phd.user')->addCommand('phabricator/ $ ./bin/phd restart');
             break;
         }
     }
 }
 private function buildRepositoryStatus(PhabricatorRepository $repository)
 {
     $viewer = $this->getRequest()->getUser();
     $is_cluster = $repository->getAlmanacServicePHID();
     $view = new PHUIStatusListView();
     $messages = id(new PhabricatorRepositoryStatusMessage())->loadAllWhere('repositoryID = %d', $repository->getID());
     $messages = mpull($messages, null, 'getStatusType');
     if ($repository->isTracked()) {
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Repository Active')));
     } else {
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'bluegrey')->setTarget(pht('Repository Inactive'))->setNote(pht('Activate this repository to begin or resume import.')));
         return $view;
     }
     $binaries = array();
     $svnlook_check = false;
     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;
     }
     if ($repository->isHosted()) {
         if ($repository->getServeOverHTTP() != PhabricatorRepository::SERVE_OFF) {
             switch ($repository->getVersionControlSystem()) {
                 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
                     $binaries[] = 'git-http-backend';
                     break;
                 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                     $binaries[] = 'svnserve';
                     $binaries[] = 'svnadmin';
                     $binaries[] = 'svnlook';
                     $svnlook_check = true;
                     break;
                 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                     $binaries[] = 'hg';
                     break;
             }
         }
         if ($repository->getServeOverSSH() != PhabricatorRepository::SERVE_OFF) {
             switch ($repository->getVersionControlSystem()) {
                 case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
                     $binaries[] = 'git-receive-pack';
                     $binaries[] = 'git-upload-pack';
                     break;
                 case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
                     $binaries[] = 'svnserve';
                     $binaries[] = 'svnadmin';
                     $binaries[] = 'svnlook';
                     $svnlook_check = true;
                     break;
                 case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
                     $binaries[] = 'hg';
                     break;
             }
         }
     }
     $binaries = array_unique($binaries);
     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)));
             }
         }
         // 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 `%s`. ' . 'You need to configure %s and include %s.', 'environment.append-paths', $this->getEnvConfigLink(), $path)));
                 }
             }
         }
     }
     $doc_href = PhabricatorEnv::getDocLink('Managing Daemons with phd');
     $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) {
         // 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.
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Pull Daemon Running')));
     } else {
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->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())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Task Daemon Running')));
     } else {
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Task Daemon Not Running'))->setNote($daemon_instructions));
     }
     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()) {
             $local_parent = dirname($repository->getLocalPath());
             if (Filesystem::pathExists($local_parent)) {
                 $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Storage Directory OK'))->setNote(phutil_tag('tt', array(), $local_parent)));
             } else {
                 $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->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;
             }
             $local_path = $repository->getLocalPath();
             $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_INIT);
             if ($message) {
                 switch ($message->getStatusCode()) {
                     case PhabricatorRepositoryStatusMessage::CODE_ERROR:
                         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Initialization Error'))->setNote($message->getParameter('message')));
                         return $view;
                     case PhabricatorRepositoryStatusMessage::CODE_OKAY:
                         if (Filesystem::pathExists($local_path)) {
                             $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Working Copy OK'))->setNote(phutil_tag('tt', array(), $local_path)));
                         } else {
                             $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->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())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')->setTarget(pht('Initializing Working Copy'))->setNote(pht('Daemons are initializing the working copy.')));
                         return $view;
                     default:
                         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Unknown Init Status'))->setNote($message->getStatusCode()));
                         return $view;
                 }
             } else {
                 $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')->setTarget(pht('No Working Copy Yet'))->setNote(pht('Waiting for daemons to build a working copy.')));
                 return $view;
             }
         }
     }
     $message = idx($messages, PhabricatorRepositoryStatusMessage::TYPE_FETCH);
     if ($message) {
         switch ($message->getStatusCode()) {
             case PhabricatorRepositoryStatusMessage::CODE_ERROR:
                 $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);
                 }
                 $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_WARNING, 'red')->setTarget(pht('Update Error'))->setNote($message));
                 return $view;
             case PhabricatorRepositoryStatusMessage::CODE_OKAY:
                 $ago = PhabricatorTime::getNow() - $message->getEpoch();
                 $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Updates OK'))->setNote(pht('Last updated %s (%s ago).', phabricator_datetime($message->getEpoch(), $viewer), phutil_format_relative_time_detailed($ago))));
                 break;
         }
     } else {
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'orange')->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;
         }
         // 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.98999999999999) {
             $percentage = 99.98999999999999;
         }
         $percentage = sprintf('%.2f%%', $percentage);
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green')->setTarget(pht('Importing'))->setNote(pht('%s Complete', $percentage)));
     } else {
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_ACCEPT, 'green')->setTarget(pht('Fully Imported')));
     }
     if (idx($messages, PhabricatorRepositoryStatusMessage::TYPE_NEEDS_UPDATE)) {
         $view->addItem(id(new PHUIStatusItemView())->setIcon(PHUIStatusItemView::ICON_UP, 'indigo')->setTarget(pht('Prioritized'))->setNote(pht('This repository will be updated soon!')));
     }
     return $view;
 }
 private function buildJumpPanel($query = null)
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $uniq_id = celerity_generate_unique_node_id();
     Javelin::initBehavior('phabricator-autofocus', array('id' => $uniq_id));
     require_celerity_resource('phabricator-jump-nav');
     $doc_href = PhabricatorEnv::getDocLink('article/Jump_Nav_User_Guide.html');
     $doc_link = phutil_render_tag('a', array('href' => $doc_href), 'Jump Nav User Guide');
     $jump_input = phutil_render_tag('input', array('type' => 'text', 'class' => 'phabricator-jump-nav', 'name' => 'jump', 'id' => $uniq_id, 'value' => $query));
     $jump_caption = phutil_render_tag('p', array('class' => 'phabricator-jump-nav-caption'), 'Enter the name of an object like <tt>D123</tt> to quickly jump to ' . 'it. See ' . $doc_link . ' or type <tt>help</tt>.');
     $panel = new AphrontPanelView();
     $panel->addClass('aphront-unpadded-panel-view');
     $panel->appendChild(phabricator_render_form($user, array('action' => '/jump/', 'method' => 'POST', 'class' => 'phabricator-jump-nav-form'), $jump_input . $jump_caption));
     return $panel;
 }
 protected final function getInboundEmailSupportLink()
 {
     return PhabricatorEnv::getDocLink('Configuring Inbound Email');
 }
 public function getOptions()
 {
     $caches_href = PhabricatorEnv::getDocLink('Managing Caches');
     return array($this->newOption('syntax-highlighter.engine', 'class', 'PhutilDefaultSyntaxHighlighterEngine')->setBaseClass('PhutilSyntaxHighlighterEngine')->setSummary(pht('Default non-pygments syntax highlighter engine.'))->setDescription(pht('Phabricator can highlight PHP by default and use Pygments for ' . 'other languages if enabled. You can provide a custom ' . 'highlighter engine by extending class %s.', 'PhutilSyntaxHighlighterEngine')), $this->newOption('pygments.enabled', 'bool', false)->setSummary(pht('Should Phabricator use Pygments to highlight code?'))->setBoolOptions(array(pht('Use Pygments'), pht('Do Not Use Pygments')))->setDescription(pht('Phabricator supports syntax highlighting a few languages by ' . 'default, but you can install Pygments (a third-party syntax ' . 'highlighting tool) to provide support for many more languages.' . "\n\n" . 'To install Pygments, visit ' . '[[ http://pygments.org | pygments.org ]] and follow the ' . 'download and install instructions.' . "\n\n" . 'Once Pygments is installed, enable this option ' . '(`pygments.enabled`) to make Phabricator use Pygments when ' . 'highlighting source code.' . "\n\n" . 'After you install and enable Pygments, newly created source ' . 'code (like diffs and pastes) should highlight correctly. ' . 'You may need to clear Phabricator\'s caches to get previously ' . 'existing source code to highlight. For instructions on ' . 'managing caches, see [[ %s | Managing Caches ]].', $caches_href)), $this->newOption('pygments.dropdown-choices', 'wild', array('apacheconf' => 'Apache Configuration', 'bash' => 'Bash Scripting', 'brainfuck' => 'Brainf*ck', 'c' => 'C', 'coffee-script' => 'CoffeeScript', 'cpp' => 'C++', 'csharp' => 'C#', 'css' => 'CSS', 'd' => 'D', 'diff' => 'Diff', 'django' => 'Django Templating', 'docker' => 'Docker', 'erb' => 'Embedded Ruby/ERB', 'erlang' => 'Erlang', 'go' => 'Golang', 'groovy' => 'Groovy', 'haskell' => 'Haskell', 'html' => 'HTML', 'http' => 'HTTP', 'invisible' => 'Invisible', 'java' => 'Java', 'js' => 'Javascript', 'json' => 'JSON', 'make' => 'Makefile', 'mysql' => 'MySQL', 'nginx' => 'Nginx Configuration', 'objc' => 'Objective-C', 'perl' => 'Perl', 'php' => 'PHP', 'postgresql' => 'PostgreSQL', 'pot' => 'Gettext Catalog', 'puppet' => 'Puppet', 'python' => 'Python', 'rainbow' => 'Rainbow', 'remarkup' => 'Remarkup', 'rst' => 'reStructuredText', 'robotframework' => 'RobotFramework', 'ruby' => 'Ruby', 'sql' => 'SQL', 'tex' => 'LaTeX', 'text' => 'Plain Text', 'twig' => 'Twig', 'xml' => 'XML', 'yaml' => 'YAML'))->setSummary(pht('Set the language list which appears in dropdowns.'))->setDescription(pht('In places that we display a dropdown to syntax-highlight code, ' . 'this is where that list is defined.')), $this->newOption('syntax.filemap', 'wild', array('@\\.arcconfig$@' => 'js', '@\\.arclint$@' => 'js', '@\\.divinerconfig$@' => 'js'))->setSummary(pht('Override what language files (based on filename) highlight as.'))->setDescription(pht('This is an override list of regular expressions which allows ' . 'you to choose what language files are highlighted as. If your ' . 'projects have certain rules about filenames or use unusual or ' . 'ambiguous language extensions, you can create a mapping here. ' . 'This is an ordered dictionary of regular expressions which will ' . 'be tested against the filename. They should map to either an ' . 'explicit language as a string value, or a numeric index into ' . 'the captured groups as an integer.'))->addExample('{"@\\.xyz$@": "php"}', pht('Highlight %s as PHP.', '*.xyz'))->addExample('{"@/httpd\\.conf@": "apacheconf"}', pht('Highlight httpd.conf as "apacheconf".'))->addExample('{"@\\.([^.]+)\\.bak$@": 1}', pht("Treat all '*.x.bak' file as '.x'. NOTE: We map to capturing group " . "1 by specifying the mapping as '1'")));
 }