diff --git a/resources/sql/patches/013.commitdetail.sql b/resources/sql/patches/013.commitdetail.sql new file mode 100644 index 000000000..940a1717d --- /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 6736571ba..55ef58e9a 100644 --- a/src/applications/diffusion/controller/base/DiffusionController.php +++ b/src/applications/diffusion/controller/base/DiffusionController.php @@ -1,240 +1,238 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ abstract class DiffusionController extends PhabricatorController { protected $diffusionRequest; public function willProcessRequest(array $data) { $this->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 e6cb4318a..5d73afcab 100644 --- a/src/applications/diffusion/controller/change/DiffusionChangeController.php +++ b/src/applications/diffusion/controller/change/DiffusionChangeController.php @@ -1,61 +1,60 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class DiffusionChangeController extends DiffusionController { public function processRequest() { $drequest = $this->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[] = '<div class="differential-primary-pane">'. $changeset_view->render(). '</div>'; - $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 575348a30..4f515f0e5 100644 --- a/src/applications/diffusion/controller/commit/DiffusionCommitController.php +++ b/src/applications/diffusion/controller/commit/DiffusionCommitController.php @@ -1,150 +1,171 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class DiffusionCommitController extends DiffusionController { public function processRequest() { $drequest = $this->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( '<div class="diffusion-commit-view">'. '<div class="diffusion-commit-dateline">'. 'r'.$callsign.$commit->getCommitIdentifier(). ' · '. date('F jS, Y g:i A', $commit->getEpoch()). '</div>'. '<h1>Revision Detail</h1>'. '<div class="diffusion-commit-details">'. '<table class="diffusion-commit-properties">'. '<tr>'. '<th>Author:</th>'. '<td>'.phutil_escape_html($commit_data->getAuthorName()).'</td>'. '</tr>'. '</table>'. '<hr />'. '<div class="diffusion-commit-message phabricator-remarkup">'. $engine->markupText($commit_data->getCommitMessage()). '</div>'. '</div>'. '</div>'); $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 = '<div class="differential-primary-pane">'. $change_list->render(). '</div>'; } else { $change_list = '<div style="margin: 2em; color: #666; padding: 1em; background: #eee;">'. '(no changes blah blah)'. '</div>'; } $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 ac585c939..578fd0f94 100644 --- a/src/applications/diffusion/controller/commit/__init__.php +++ b/src/applications/diffusion/controller/commit/__init__.php @@ -1,25 +1,27 @@ <?php /** * This file is automatically generated. Lint this module to rebuild it. * @generated */ +phutil_require_module('phabricator', 'applications/differential/constants/changetype'); phutil_require_module('phabricator', 'applications/differential/parser/markup'); phutil_require_module('phabricator', 'applications/differential/view/changesetlistview'); phutil_require_module('phabricator', 'applications/diffusion/controller/base'); phutil_require_module('phabricator', 'applications/diffusion/data/pathchange'); phutil_require_module('phabricator', 'applications/diffusion/query/pathchange/base'); phutil_require_module('phabricator', 'applications/diffusion/view/commitchangetable'); +phutil_require_module('phabricator', 'applications/repository/constants/repositorytype'); phutil_require_module('phabricator', 'applications/repository/storage/repository'); phutil_require_module('phabricator', 'infrastructure/celerity/api'); phutil_require_module('phabricator', 'storage/queryfx'); phutil_require_module('phabricator', 'view/form/error'); phutil_require_module('phabricator', 'view/layout/panel'); phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils'); phutil_require_source('DiffusionCommitController.php'); diff --git a/src/applications/diffusion/query/diff/git/DiffusionGitDiffQuery.php b/src/applications/diffusion/query/diff/git/DiffusionGitDiffQuery.php index 38245cb4b..38099827b 100644 --- a/src/applications/diffusion/query/diff/git/DiffusionGitDiffQuery.php +++ b/src/applications/diffusion/query/diff/git/DiffusionGitDiffQuery.php @@ -1,61 +1,61 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ final class DiffusionGitDiffQuery extends DiffusionDiffQuery { protected function executeQuery() { $drequest = $this->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 17a8b4ac4..114f3781e 100644 --- a/src/applications/diffusion/query/diff/svn/__init__.php +++ b/src/applications/diffusion/query/diff/svn/__init__.php @@ -1,23 +1,24 @@ <?php /** * This file is automatically generated. Lint this module to rebuild it. * @generated */ phutil_require_module('arcanist', 'parser/diff'); phutil_require_module('phabricator', 'applications/differential/constants/changetype'); phutil_require_module('phabricator', 'applications/differential/storage/diff'); +phutil_require_module('phabricator', 'applications/diffusion/data/pathchange'); phutil_require_module('phabricator', 'applications/diffusion/query/diff/base'); phutil_require_module('phabricator', 'applications/diffusion/query/pathchange/base'); phutil_require_module('phutil', 'filesystem'); phutil_require_module('phutil', 'filesystem/tempfile'); phutil_require_module('phutil', 'future'); phutil_require_module('phutil', 'future/exec'); phutil_require_module('phutil', 'utils'); phutil_require_source('DiffusionSvnDiffQuery.php'); diff --git a/src/applications/diffusion/request/git/DiffusionGitRequest.php b/src/applications/diffusion/request/git/DiffusionGitRequest.php index 56351b65e..f215aabfe 100644 --- a/src/applications/diffusion/request/git/DiffusionGitRequest.php +++ b/src/applications/diffusion/request/git/DiffusionGitRequest.php @@ -1,121 +1,128 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class DiffusionGitRequest extends DiffusionRequest { protected function initializeFromAphrontRequestDictionary() { parent::initializeFromAphrontRequestDictionary(); $path = $this->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 72c11b159..8d3623355 100644 --- a/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php +++ b/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php @@ -1,83 +1,84 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ final class DiffusionCommitChangeTableView extends DiffusionView { private $pathChanges; public function setPathChanges(array $path_changes) { $this->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 1e4cf5e92..119393a13 100644 --- a/src/applications/repository/storage/commitdata/PhabricatorRepositoryCommitData.php +++ b/src/applications/repository/storage/commitdata/PhabricatorRepositoryCommitData.php @@ -1,31 +1,35 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class PhabricatorRepositoryCommitData extends PhabricatorRepositoryDAO { protected $commitID; protected $authorName; protected $commitMessage; + protected $commitDetails = array(); public function getConfiguration() { return array( self::CONFIG_TIMESTAMPS => 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 87ce4a69d..fade2cda7 100644 --- a/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php +++ b/src/applications/repository/worker/base/PhabricatorRepositoryCommitParserWorker.php @@ -1,103 +1,106 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ abstract class PhabricatorRepositoryCommitParserWorker extends PhabricatorWorker { protected $commit; + protected $repository; final public function doWork() { $commit_id = $this->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 2c893c206..42f60905c 100644 --- a/webroot/index.php +++ b/webroot/index.php @@ -1,179 +1,180 @@ <?php /* * Copyright 2011 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ error_reporting(E_ALL | E_STRICT); +ini_set('memory_limit', -1); $env = getenv('PHABRICATOR_ENV'); // Apache if (!$env) { if (isset($_ENV['PHABRICATOR_ENV'])) { $env = $_ENV['PHABRICATOR_ENV']; } } if (!$env) { phabricator_fatal_config_error( "The 'PHABRICATOR_ENV' environmental variable is not defined. Modify ". "your httpd.conf to include 'SetEnv PHABRICATOR_ENV <env>', where '<env>' ". "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 = '<div style="text-align: center; background: #ff00ff; padding: 1em; font-size: 24px; font-weight: bold;">'. '<a href="/xhprof/profile/'.$profile.'/">'. '>>> View Profile <<<'. '</a>'. '</div>'; if (strpos($response_string, '<body>') !== false) { $response_string = str_replace( '<body>', '<body>'.$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(); }