diff --git a/resources/sql/patches/013.commitdetail.sql b/resources/sql/patches/013.commitdetail.sql
new file mode 100644
index 0000000000..940a1717d4
--- /dev/null
+++ b/resources/sql/patches/013.commitdetail.sql
@@ -0,0 +1,2 @@
+ALTER TABLE phabricator_repository.repository_commitdata
+ ADD commitDetails LONGBLOB NOT NULL;
diff --git a/src/applications/diffusion/controller/base/DiffusionController.php b/src/applications/diffusion/controller/base/DiffusionController.php
index 6736571ba6..55ef58e9ac 100644
--- a/src/applications/diffusion/controller/base/DiffusionController.php
+++ b/src/applications/diffusion/controller/base/DiffusionController.php
@@ -1,240 +1,238 @@
diffusionRequest = DiffusionRequest::newFromAphrontRequestDictionary(
$data);
}
public function setDiffusionRequest(DiffusionRequest $request) {
$this->diffusionRequest = $request;
return $this;
}
protected function getDiffusionRequest() {
return $this->diffusionRequest;
}
public function buildStandardPageResponse($view, array $data) {
$page = $this->buildStandardPageView();
$page->setApplicationName('Diffusion');
$page->setBaseURI('/diffusion/');
$page->setTitle(idx($data, 'title'));
$page->setGlyph("\xE2\x89\x88");
$page->appendChild($view);
$response = new AphrontWebpageResponse();
return $response->setContent($page->render());
}
final protected function buildSideNav($selected, $has_change_view) {
$nav = new AphrontSideNavView();
$navs = array(
'history' => 'History View',
'browse' => 'Browse View',
'change' => 'Change View',
);
if (!$has_change_view) {
unset($navs['change']);
}
$drequest = $this->getDiffusionRequest();
$repository = $drequest->getRepository();
$callsign = $repository->getCallsign();
$branch_uri = $drequest->getBranchURIComponent($drequest->getBranch());
$path_uri = $branch_uri.$drequest->getPath();
$commit_uri = null;
$raw_commit = $drequest->getRawCommit();
if ($raw_commit) {
$commit_uri = ';'.$drequest->getCommitURIComponent($raw_commit);
}
foreach ($navs as $uri => $name) {
$nav->addNavItem(
phutil_render_tag(
'a',
array(
'href' => "/diffusion/{$callsign}/{$uri}/{$path_uri}{$commit_uri}",
'class' =>
($uri == $selected
? 'aphront-side-nav-selected'
: null),
),
$name));
}
return $nav;
}
public function buildCrumbs(array $spec = array()) {
- $drequest = $this->diffusionRequest;
-
$crumbs = new AphrontCrumbsView();
+ $crumb_list = $this->buildCrumbList($spec);
+ $crumbs->setCrumbs($crumb_list);
+ return $crumbs;
+ }
+
+ private function buildCrumbList(array $spec = array()) {
+ $drequest = $this->getDiffusionRequest();
$crumb_list = array();
$repository = $drequest->getRepository();
if ($repository) {
$crumb_list[] = phutil_render_tag(
'a',
array(
'href' => '/diffusion/',
),
'Diffusion');
} else {
$crumb_list[] = 'Diffusion';
- $crumbs->setCrumbs($crumb_list);
- return $crumbs;
+ return $crumb_list;
}
$callsign = $repository->getCallsign();
$repository_name = phutil_escape_html($repository->getName()).' Repository';
$branch_name = $drequest->getBranch();
if ($branch_name) {
$repository_name .= ' ('.phutil_escape_html($branch_name).')';
}
$branch_uri = $drequest->getBranchURIComponent($drequest->getBranch());
if (empty($spec['view']) && empty($spec['commit'])) {
$crumb_list[] = $repository_name;
- $crumbs->setCrumbs($crumb_list);
- return $crumbs;
+ return $crumb_list;
}
$crumb_list[] = phutil_render_tag(
'a',
array(
'href' => "/diffusion/{$callsign}/",
),
$repository_name);
$raw_commit = $drequest->getRawCommit();
if (isset($spec['commit'])) {
$crumb_list[] = "r{$callsign}{$raw_commit}";
- $crumbs->setCrumbs($crumb_list);
- return $crumbs;
+ return $crumb_list;
}
$view = $spec['view'];
$path = null;
if (isset($spec['path'])) {
$path = $drequest->getPath();
}
if ($raw_commit) {
$commit_link = DiffusionView::linkCommit(
$repository,
$raw_commit);
} else {
$commit_link = '';
}
switch ($view) {
case 'history':
$view_name = 'History';
break;
case 'browse':
$view_name = 'Browse';
break;
case 'change':
$view_name = 'Change';
$crumb_list[] = phutil_escape_html($path).' ('.$commit_link.')';
- $crumbs->setCrumbs($crumb_list);
- return $crumbs;
+ return $crumb_list;
}
$view_root_uri = "/diffusion/{$callsign}/{$view}/{$branch_uri}";
$jump_href = $view_root_uri;
$view_tail_uri = null;
if ($raw_commit) {
$view_tail_uri = ';'.$drequest->getCommitURIComponent($raw_commit);
}
if (!strlen($path)) {
$crumb_list[] = $view_name;
} else {
$crumb_list[] = phutil_render_tag(
'a',
array(
'href' => $view_root_uri.$view_tail_uri,
),
$view_name);
$path_parts = explode('/', $path);
do {
$last = array_pop($path_parts);
} while ($last == '');
$path_sections = array();
$thus_far = '';
foreach ($path_parts as $path_part) {
$thus_far .= $path_part.'/';
$path_sections[] = phutil_render_tag(
'a',
array(
'href' => $view_root_uri.$thus_far.$view_tail_uri,
),
phutil_escape_html($path_part));
}
$path_sections[] = phutil_escape_html($last);
$path_sections = '/'.implode('/', $path_sections);
$jump_href = $view_root_uri.$thus_far.$last;
$crumb_list[] = $path_sections;
}
$last_crumb = array_pop($crumb_list);
if ($raw_commit) {
$jump_link = phutil_render_tag(
'a',
array(
'href' => $jump_href,
),
'Jump to HEAD');
$last_crumb .= " @ {$commit_link} ({$jump_link})";
} else {
$last_crumb .= " @ HEAD";
}
$crumb_list[] = $last_crumb;
-
- $crumbs->setCrumbs($crumb_list);
-
- return $crumbs;
+ return $crumb_list;
}
}
diff --git a/src/applications/diffusion/controller/change/DiffusionChangeController.php b/src/applications/diffusion/controller/change/DiffusionChangeController.php
index e6cb4318ab..5d73afcab7 100644
--- a/src/applications/diffusion/controller/change/DiffusionChangeController.php
+++ b/src/applications/diffusion/controller/change/DiffusionChangeController.php
@@ -1,61 +1,60 @@
diffusionRequest;
$content = array();
$content[] = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'change',
));
$diff_query = DiffusionDiffQuery::newFromDiffusionRequest($drequest);
$changeset = $diff_query->loadChangeset();
$changeset_view = new DifferentialChangesetListView();
$changeset_view->setChangesets(array($changeset));
$changeset_view->setRenderURI(
'/diffusion/'.$drequest->getRepository()->getCallsign().'/diff/');
// TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better.
require_celerity_resource('differential-core-view-css');
$content[] =
'
'.
$changeset_view->render().
'
';
-
$nav = $this->buildSideNav('change', true);
$nav->appendChild($content);
return $this->buildStandardPageResponse(
$nav,
array(
'title' => 'Change',
));
}
}
diff --git a/src/applications/diffusion/controller/commit/DiffusionCommitController.php b/src/applications/diffusion/controller/commit/DiffusionCommitController.php
index 575348a302..4f515f0e55 100644
--- a/src/applications/diffusion/controller/commit/DiffusionCommitController.php
+++ b/src/applications/diffusion/controller/commit/DiffusionCommitController.php
@@ -1,150 +1,171 @@
getDiffusionRequest();
$callsign = $drequest->getRepository()->getCallsign();
$content = array();
$content[] = $this->buildCrumbs(array(
'commit' => true,
));
$detail_panel = new AphrontPanelView();
$repository = $drequest->getRepository();
$commit = $drequest->loadCommit();
if (!$commit) {
// TODO: Make more user-friendly.
throw new Exception('This commit has not parsed yet.');
}
$commit_data = $drequest->loadCommitData();
$factory = new DifferentialMarkupEngineFactory();
$engine = $factory->newDifferentialCommentMarkupEngine();
require_celerity_resource('diffusion-commit-view-css');
require_celerity_resource('phabricator-remarkup-css');
$detail_panel->appendChild(
''.
'
'.
'r'.$callsign.$commit->getCommitIdentifier().
' · '.
date('F jS, Y g:i A', $commit->getEpoch()).
'
'.
'
Revision Detail
'.
'
'.
'
'.
''.
'| Author: | '.
''.phutil_escape_html($commit_data->getAuthorName()).' | '.
'
'.
'
'.
'
'.
''.
'
'.
'
');
$content[] = $detail_panel;
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
$drequest);
$changes = $change_query->loadChanges();
$change_table = new DiffusionCommitChangeTableView();
$change_table->setDiffusionRequest($drequest);
$change_table->setPathChanges($changes);
// TODO: Large number of modified files check.
$count = number_format(count($changes));
$bad_commit = null;
if ($count == 0) {
$bad_commit = queryfx_one(
id(new PhabricatorRepository())->establishConnection('r'),
'SELECT * FROM %T WHERE fullCommitName = %s',
PhabricatorRepository::TABLE_BADCOMMIT,
'r'.$callsign.$commit->getCommitIdentifier());
}
if ($bad_commit) {
$error_panel = new AphrontErrorView();
$error_panel->setWidth(AphrontErrorView::WIDTH_WIDE);
$error_panel->setTitle('Bad Commit');
$error_panel->appendChild(
phutil_escape_html($bad_commit['description']));
$content[] = $error_panel;
} else {
$change_panel = new AphrontPanelView();
$change_panel->setHeader("Changes ({$count})");
$change_panel->appendChild($change_table);
$content[] = $change_panel;
if ($changes) {
$changesets = DiffusionPathChange::convertToDifferentialChangesets(
$changes);
- foreach ($changesets as $changeset) {
+
+ $vcs = $repository->getVersionControlSystem();
+ switch ($vcs) {
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
+ $vcs_supports_directory_changes = true;
+ break;
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
+ $vcs_supports_directory_changes = false;
+ break;
+ default:
+ throw new Exception("Unknown VCS.");
+ }
+
+ foreach ($changesets as $key => $changeset) {
+ $file_type = $changeset->getFileType();
+ if ($file_type == DifferentialChangeType::FILE_DIRECTORY) {
+ if (!$vcs_supports_directory_changes) {
+ unset($changesets[$key]);
+ continue;
+ }
+ }
+
$branch = $drequest->getBranchURIComponent(
$drequest->getBranch());
$filename = $changeset->getFilename();
$commit = $drequest->getCommit();
$reference = "{$branch}{$filename};{$commit}";
$changeset->setRenderingReference($reference);
}
$change_list = new DifferentialChangesetListView();
$change_list->setChangesets($changesets);
$change_list->setRenderURI('/diffusion/'.$callsign.'/diff/');
// TODO: This is pretty awkward, unify the CSS between Diffusion and
// Differential better.
require_celerity_resource('differential-core-view-css');
$change_list =
''.
$change_list->render().
'
';
} else {
$change_list =
''.
'(no changes blah blah)'.
'
';
}
$content[] = $change_list;
}
return $this->buildStandardPageResponse(
$content,
array(
'title' => 'Diffusion',
));
}
}
diff --git a/src/applications/diffusion/controller/commit/__init__.php b/src/applications/diffusion/controller/commit/__init__.php
index ac585c939a..578fd0f942 100644
--- a/src/applications/diffusion/controller/commit/__init__.php
+++ b/src/applications/diffusion/controller/commit/__init__.php
@@ -1,25 +1,27 @@
getRequest();
$repository = $drequest->getRepository();
$options = array(
'-M',
'-C',
'--no-ext-diff',
'--no-color',
'--src-prefix=a/',
'--dst-prefix=b/',
'-U65535',
);
$options = implode(' ', $options);
list($raw_diff) = execx(
"(cd %s && git diff {$options} %s^ %s -- %s)",
$repository->getDetail('local-path'),
$drequest->getCommit(),
$drequest->getCommit(),
$drequest->getPath());
$parser = new ArcanistDiffParser();
$parser->setDetectBinaryFiles(true);
$changes = $parser->parseDiff($raw_diff);
$diff = DifferentialDiff::newFromRawChanges($changes);
$changesets = $diff->getChangesets();
$changeset = reset($changesets);
$id =
- $drequest->getBranch().'/'.
+ $drequest->getBranchURIComponent($drequest->getBranch()).
$drequest->getPath().';'.
$drequest->getCommit();
$changeset->setID($id);
return $changeset;
}
}
diff --git a/src/applications/diffusion/query/diff/svn/__init__.php b/src/applications/diffusion/query/diff/svn/__init__.php
index 17a8b4ac46..114f3781e6 100644
--- a/src/applications/diffusion/query/diff/svn/__init__.php
+++ b/src/applications/diffusion/query/diff/svn/__init__.php
@@ -1,23 +1,24 @@
path;
$parts = explode('/', $path);
$branch = array_shift($parts);
$this->branch = $this->decodeBranchName($branch);
foreach ($parts as $key => $part) {
// Prevent any hyjinx since we're ultimately shipping this to the
// filesystem under a lot of git workflows.
if ($part == '..') {
unset($parts[$key]);
}
}
$this->path = implode('/', $parts);
if ($this->repository) {
$local_path = $this->repository->getDetail('local-path');
// TODO: This is not terribly efficient and does not produce terribly
// good error messages, but it seems better to put error handling code
// here than to try to do it in every query.
$branch = $this->getBranch();
execx(
'(cd %s && git rev-parse --verify %s)',
$local_path,
$branch);
if ($this->commit) {
list($commit) = execx(
'(cd %s && git rev-parse --verify %s)',
$local_path,
$this->commit);
// Beyond verifying them, expand commit short forms to full 40-character
// sha1s.
$this->commit = trim($commit);
+/*
+
+ TODO: Unclear if this is actually a good idea or not; it breaks commit views
+ at the very least.
+
list($contains) = execx(
'(cd %s && git branch --contains %s)',
$local_path,
$this->commit);
$contains = array_filter(explode("\n", $contains));
$found = false;
foreach ($contains as $containing_branch) {
$containing_branch = trim($containing_branch, "* \n");
if ($containing_branch == $branch) {
$found = true;
break;
}
}
if (!$found) {
throw new Exception(
"Commit does not exist on this branch!");
}
+*/
+
}
}
}
public function getBranch() {
if ($this->branch) {
return $this->branch;
}
if ($this->repository) {
- return $this->repository->getDetail('default-branch', 'master');
+ return $this->repository->getDetail('default-branch', 'origin/master');
}
throw new Exception("Unable to determine branch!");
}
public function getUriPath() {
return '/diffusion/'.$this->getCallsign().'/browse/'.
$this->branch.'/'.$this->path;
}
public function getCommit() {
if ($this->commit) {
return $this->commit;
}
return $this->getBranch();
}
public function getBranchURIComponent($branch) {
return $this->encodeBranchName($branch).'/';
}
private function decodeBranchName($branch) {
return str_replace(':', '/', $branch);
}
private function encodeBranchName($branch) {
return str_replace('/', ':', $branch);
}
}
diff --git a/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php b/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php
index 72c11b1598..8d3623355c 100644
--- a/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php
+++ b/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php
@@ -1,83 +1,84 @@
pathChanges = $path_changes;
return $this;
}
public function render() {
$rows = array();
// TODO: Experiment with path stack rendering.
// TODO: Copy Away and Move Away are rendered junkily still.
foreach ($this->pathChanges as $change) {
$change_verb = DifferentialChangeType::getFullNameForChangeType(
$change->getChangeType());
- $suffix = null;
+ $path = $change->getPath();
if ($change->getFileType() == DifferentialChangeType::FILE_DIRECTORY) {
- $suffix = '/';
- }
+ $path_column = phutil_escape_html($path).'/';
+ } else {
+ $hash = substr(md5($path), 0, 8);
- $path = $change->getPath();
- $hash = substr(sha1($path), 0, 7);
+ $path_column = phutil_render_tag(
+ 'a',
+ array(
+ 'href' => '#'.$hash,
+ ),
+ phutil_escape_html($path));
+ }
$rows[] = array(
$this->linkHistory($change->getPath()),
$this->linkBrowse($change->getPath()),
$this->linkChange(
$change->getChangeType(),
$change->getFileType(),
$change->getPath()),
- phutil_render_tag(
- 'a',
- array(
- 'href' => '#'.$hash,
- ),
- phutil_escape_html($path).$suffix),
+ $path_column,
);
}
$view = new AphrontTableView($rows);
$view->setHeaders(
array(
'History',
'Browse',
'Change',
'Path',
));
$view->setColumnClasses(
array(
'',
'',
'',
'wide',
));
$view->setNoDataString('This change has not been fully parsed yet.');
return $view->render();
}
}
diff --git a/src/applications/repository/storage/commitdata/PhabricatorRepositoryCommitData.php b/src/applications/repository/storage/commitdata/PhabricatorRepositoryCommitData.php
index 1e4cf5e92b..119393a13f 100644
--- a/src/applications/repository/storage/commitdata/PhabricatorRepositoryCommitData.php
+++ b/src/applications/repository/storage/commitdata/PhabricatorRepositoryCommitData.php
@@ -1,31 +1,35 @@
false,
+ self::CONFIG_SERIALIZATION => array(
+ 'commitDetails' => self::SERIALIZATION_JSON,
+ ),
) + parent::getConfiguration();
}
}
diff --git a/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php b/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php
index 87ce4a69d1..fade2cda75 100644
--- a/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php
+++ b/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php
@@ -1,103 +1,106 @@
getTaskData();
if (!$commit_id) {
return;
}
$commit = id(new PhabricatorRepositoryCommit())->load($commit_id);
if (!$commit) {
// TODO: Communicate permanent failure?
return;
}
$this->commit = $commit;
$repository = id(new PhabricatorRepository())->load(
$commit->getRepositoryID());
if (!$repository) {
return;
}
+ $this->repository = $repository;
+
return $this->parseCommit($repository, $commit);
}
abstract protected function parseCommit(
PhabricatorRepository $repository,
PhabricatorRepositoryCommit $commit);
/**
* This method is kind of awkward here but both the SVN message and
* change parsers use it.
*/
protected function getSVNLogXMLObject($uri, $revision, $verbose = false) {
if ($verbose) {
$verbose = '--verbose';
}
try {
list($xml) = execx(
"svn log --xml {$verbose} --limit 1 --non-interactive %s@%d",
$uri,
$revision);
} catch (CommandException $ex) {
// HTTPS is generally faster and more reliable than svn+ssh, but some
// commit messages with non-UTF8 text can't be retrieved over HTTPS, see
// Facebook rE197184 for one example. Make an attempt to fall back to
// svn+ssh if we've failed outright to retrieve the message.
$fallback_uri = new PhutilURI($uri);
if ($fallback_uri->getProtocol() != 'https') {
throw $ex;
}
$fallback_uri->setProtocol('svn+ssh');
list($xml) = execx(
"svn log --xml {$verbose} --limit 1 --non-interactive %s@%d",
$fallback_uri,
$revision);
}
// Subversion may send us back commit messages which won't parse because
// they have non UTF-8 garbage in them. Slam them into valid UTF-8.
$xml = phutil_utf8ize($xml);
return new SimpleXMLElement($xml);
}
protected function isBadCommit($full_commit_name) {
$repository = new PhabricatorRepository();
$bad_commit = queryfx_one(
$repository->establishConnection('w'),
'SELECT * FROM %T WHERE fullCommitName = %s',
PhabricatorRepository::TABLE_BADCOMMIT,
$full_commit_name);
return (bool)$bad_commit;
}
}
diff --git a/webroot/index.php b/webroot/index.php
index 2c893c2060..42f60905c4 100644
--- a/webroot/index.php
+++ b/webroot/index.php
@@ -1,179 +1,180 @@
', where '' ".
"is one of 'development', 'production', or a custom environment.");
}
if (!function_exists('mysql_connect')) {
phabricator_fatal_config_error(
"The PHP MySQL extension is not installed. This extension is required.");
}
if (!isset($_REQUEST['__path__'])) {
phabricator_fatal_config_error(
"__path__ is not set. Your rewrite rules are not configured correctly.");
}
require_once dirname(dirname(__FILE__)).'/conf/__init_conf__.php';
$conf = phabricator_read_config_file($env);
$conf['phabricator.env'] = $env;
setup_aphront_basics();
phutil_require_module('phabricator', 'infrastructure/env');
PhabricatorEnv::setEnvConfig($conf);
phutil_require_module('phabricator', 'aphront/console/plugin/xhprof/api');
DarkConsoleXHProfPluginAPI::hookProfiler();
phutil_require_module('phabricator', 'aphront/console/plugin/errorlog/api');
set_error_handler(array('DarkConsoleErrorLogPluginAPI', 'handleError'));
set_exception_handler(array('DarkConsoleErrorLogPluginAPI', 'handleException'));
foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
phutil_load_library($library);
}
$host = $_SERVER['HTTP_HOST'];
$path = $_REQUEST['__path__'];
switch ($host) {
default:
$config_key = 'aphront.default-application-configuration-class';
$config_class = PhabricatorEnv::getEnvConfig($config_key);
PhutilSymbolLoader::loadClass($config_class);
$application = newv($config_class, array());
break;
}
$application->setHost($host);
$application->setPath($path);
$application->willBuildRequest();
$request = $application->buildRequest();
$application->setRequest($request);
list($controller, $uri_data) = $application->buildController();
try {
$response = $controller->willBeginExecution();
if (!$response) {
$controller->willProcessRequest($uri_data);
$response = $controller->processRequest();
}
} catch (AphrontRedirectException $ex) {
$response = id(new AphrontRedirectResponse())
->setURI($ex->getURI());
} catch (Exception $ex) {
$response = $application->handleException($ex);
}
$response = $application->willSendResponse($response);
$response->setRequest($request);
$response_string = $response->buildResponseString();
$code = $response->getHTTPResponseCode();
if ($code != 200) {
header("HTTP/1.0 {$code}");
}
$headers = $response->getCacheHeaders();
$headers = array_merge($headers, $response->getHeaders());
foreach ($headers as $header) {
list($header, $value) = $header;
header("{$header}: {$value}");
}
// TODO: This shouldn't be possible in a production-configured environment.
if (isset($_REQUEST['__profile__']) &&
($_REQUEST['__profile__'] == 'all')) {
$profile = DarkConsoleXHProfPluginAPI::stopProfiler();
$profile =
'';
if (strpos($response_string, '') !== false) {
$response_string = str_replace(
'',
''.$profile,
$response_string);
} else {
echo $profile;
}
}
echo $response_string;
/**
* @group aphront
*/
function setup_aphront_basics() {
$aphront_root = dirname(dirname(__FILE__));
$libraries_root = dirname($aphront_root);
$root = null;
if (!empty($_SERVER['PHUTIL_LIBRARY_ROOT'])) {
$root = $_SERVER['PHUTIL_LIBRARY_ROOT'];
}
ini_set('include_path', $libraries_root.':'.ini_get('include_path'));
@include_once $root.'libphutil/src/__phutil_library_init__.php';
if (!@constant('__LIBPHUTIL__')) {
echo "ERROR: Unable to load libphutil. Update your PHP 'include_path' to ".
"include the parent directory of libphutil/.\n";
exit(1);
}
// Load Phabricator itself using the absolute path, so we never end up doing
// anything surprising (loading index.php and libraries from different
// directories).
phutil_load_library($aphront_root.'/src');
phutil_load_library('arcanist/src');
}
function __autoload($class_name) {
PhutilSymbolLoader::loadClass($class_name);
}
function phabricator_fatal_config_error($msg) {
header('Content-Type: text/plain', $replace = true, $http_error = 500);
$error = "CONFIG ERROR: ".$msg."\n";
error_log($error);
echo $error;
die();
}