From 485b5e5ded5e545f09549f234053e46a5943fb9a Mon Sep 17 00:00:00 2001 From: epriestley Date: Sat, 12 Mar 2011 16:17:34 -0800 Subject: [PATCH] Make the Diffusion UI vaguely usable in some cases. --- resources/sql/patches/006.repository.sql | 2 + src/__celerity_resource_map__.php | 11 +- src/__phutil_library_map__.php | 22 ++- ...AphrontDefaultApplicationConfiguration.php | 7 +- .../controller/base/DiffusionController.php | 183 ++++++++++++++++++ .../diffusion/controller/base/__init__.php | 4 + .../browse/DiffusionBrowseController.php | 16 +- .../file/DiffusionBrowseFileController.php | 17 +- .../history/DiffusionHistoryController.php | 17 +- .../home/DiffusionHomeController.php | 9 +- .../DiffusionRepositoryController.php | 79 ++++++++ .../controller/repository/__init__.php | 19 ++ .../branch/DiffusionBranchInformation.php | 42 ++++ .../diffusion/data/branch/__init__.php | 10 + .../data/pathchange/DiffusionPathChange.php | 10 +- .../branch/base/DiffusionBranchQuery.php | 57 ++++++ .../diffusion/query/branch/base/__init__.php | 14 ++ .../branch/git/DiffusionGitBranchQuery.php | 52 +++++ .../diffusion/query/branch/git/__init__.php | 15 ++ .../browse/base/DiffusionBrowseQuery.php | 5 +- .../diffusion/query/browse/base/__init__.php | 2 + .../browse/svn/DiffusionSvnBrowseQuery.php | 93 +++++++++ .../diffusion/query/browse/svn/__init__.php | 17 ++ .../history/base/DiffusionHistoryQuery.php | 15 +- .../diffusion/query/history/base/__init__.php | 2 + .../history/git/DiffusionGitHistoryQuery.php | 6 +- .../history/svn/DiffusionSvnHistoryQuery.php | 60 ++++++ .../diffusion/query/history/svn/__init__.php | 17 ++ .../request/base/DiffusionRequest.php | 12 ++ .../request/git/DiffusionGitRequest.php | 12 ++ .../diffusion/view/base/DiffusionView.php | 109 +++++++++++ .../diffusion/view/base/__init__.php | 16 ++ .../branchtable/DiffusionBranchTableView.php | 63 ++++++ .../diffusion/view/branchtable/__init__.php | 15 ++ .../browsetable/DiffusionBrowseTableView.php | 38 +++- .../diffusion/view/browsetable/__init__.php | 5 +- .../DiffusionCommitChangeTableView.php | 8 +- .../view/commitchangetable/__init__.php | 2 +- .../DiffusionHistoryTableView.php | 37 +++- .../diffusion/view/historytable/__init__.php | 4 +- ...rRepositorySvnCommitChangeParserWorker.php | 9 +- src/view/base/AphrontView.php | 6 +- src/view/layout/crumbs/AphrontCrumbsView.php | 50 +++++ src/view/layout/crumbs/__init__.php | 13 ++ webroot/rsrc/css/aphront/crumbs-view.css | 18 ++ webroot/rsrc/css/aphront/table-view.css | 4 + 46 files changed, 1158 insertions(+), 66 deletions(-) create mode 100644 src/applications/diffusion/controller/repository/DiffusionRepositoryController.php create mode 100644 src/applications/diffusion/controller/repository/__init__.php create mode 100644 src/applications/diffusion/data/branch/DiffusionBranchInformation.php create mode 100644 src/applications/diffusion/data/branch/__init__.php create mode 100644 src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php create mode 100644 src/applications/diffusion/query/branch/base/__init__.php create mode 100644 src/applications/diffusion/query/branch/git/DiffusionGitBranchQuery.php create mode 100644 src/applications/diffusion/query/branch/git/__init__.php create mode 100644 src/applications/diffusion/query/browse/svn/DiffusionSvnBrowseQuery.php create mode 100644 src/applications/diffusion/query/browse/svn/__init__.php create mode 100644 src/applications/diffusion/query/history/svn/DiffusionSvnHistoryQuery.php create mode 100644 src/applications/diffusion/query/history/svn/__init__.php create mode 100644 src/applications/diffusion/view/base/DiffusionView.php create mode 100644 src/applications/diffusion/view/base/__init__.php create mode 100644 src/applications/diffusion/view/branchtable/DiffusionBranchTableView.php create mode 100644 src/applications/diffusion/view/branchtable/__init__.php create mode 100644 src/view/layout/crumbs/AphrontCrumbsView.php create mode 100644 src/view/layout/crumbs/__init__.php create mode 100644 webroot/rsrc/css/aphront/crumbs-view.css diff --git a/resources/sql/patches/006.repository.sql b/resources/sql/patches/006.repository.sql index fdca9e5517..6ea9ee3f5f 100644 --- a/resources/sql/patches/006.repository.sql +++ b/resources/sql/patches/006.repository.sql @@ -40,3 +40,5 @@ create table phabricator_repository.repository_filesystem ( fileType int unsigned not null, primary key (repositoryID, parentID, svnCommit, pathID) ); + +alter table repository_filesystem add key (repositoryID, svnCommit); \ No newline at end of file diff --git a/src/__celerity_resource_map__.php b/src/__celerity_resource_map__.php index 3cbf65f1a8..1d7f4eb5f8 100644 --- a/src/__celerity_resource_map__.php +++ b/src/__celerity_resource_map__.php @@ -7,6 +7,15 @@ */ celerity_register_resource_map(array( + 'aphront-crumbs-view-css' => + array( + 'uri' => '/res/4408ef5f/rsrc/css/aphront/crumbs-view.css', + 'type' => 'css', + 'requires' => + array( + ), + 'disk' => '/rsrc/css/aphront/crumbs-view.css', + ), 'aphront-dark-console-css' => array( 'uri' => '/res/056b0c12/rsrc/css/aphront/dark-console.css', @@ -217,7 +226,7 @@ celerity_register_resource_map(array( ), 'maniphest-transaction-detail-css' => array( - 'uri' => '/res/658912c5/rsrc/css/application/maniphest/transaction-detail.css', + 'uri' => '/res/9418efc9/rsrc/css/application/maniphest/transaction-detail.css', 'type' => 'css', 'requires' => array( diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index f130884b9b..9b91bedb95 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -13,6 +13,7 @@ phutil_register_library_map(array( 'AphrontAjaxResponse' => 'aphront/response/ajax', 'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration', 'AphrontController' => 'aphront/controller', + 'AphrontCrumbsView' => 'view/layout/crumbs', 'AphrontDatabaseConnection' => 'storage/connection/base', 'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration', 'AphrontDefaultApplicationController' => 'aphront/default/controller', @@ -142,6 +143,9 @@ phutil_register_library_map(array( 'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview', 'DifferentialSubscribeController' => 'applications/differential/controller/subscribe', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', + 'DiffusionBranchInformation' => 'applications/diffusion/data/branch', + 'DiffusionBranchQuery' => 'applications/diffusion/query/branch/base', + 'DiffusionBranchTableView' => 'applications/diffusion/view/branchtable', 'DiffusionBrowseController' => 'applications/diffusion/controller/browse', 'DiffusionBrowseFileController' => 'applications/diffusion/controller/file', 'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base', @@ -151,6 +155,7 @@ phutil_register_library_map(array( 'DiffusionController' => 'applications/diffusion/controller/base', 'DiffusionFileContent' => 'applications/diffusion/data/filecontent', 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/base', + 'DiffusionGitBranchQuery' => 'applications/diffusion/query/branch/git', 'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/git', 'DiffusionGitHistoryQuery' => 'applications/diffusion/query/history/git', @@ -160,8 +165,12 @@ phutil_register_library_map(array( 'DiffusionHistoryTableView' => 'applications/diffusion/view/historytable', 'DiffusionHomeController' => 'applications/diffusion/controller/home', 'DiffusionPathChange' => 'applications/diffusion/data/pathchange', + 'DiffusionRepositoryController' => 'applications/diffusion/controller/repository', 'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath', 'DiffusionRequest' => 'applications/diffusion/request/base', + 'DiffusionSvnBrowseQuery' => 'applications/diffusion/query/browse/svn', + 'DiffusionSvnHistoryQuery' => 'applications/diffusion/query/history/svn', + 'DiffusionView' => 'applications/diffusion/view/base', 'Javelin' => 'infrastructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', 'ManiphestController' => 'applications/maniphest/controller/base', @@ -364,6 +373,7 @@ phutil_register_library_map(array( 'Aphront400Response' => 'AphrontResponse', 'Aphront404Response' => 'AphrontResponse', 'AphrontAjaxResponse' => 'AphrontResponse', + 'AphrontCrumbsView' => 'AphrontView', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDefaultApplicationController' => 'AphrontController', 'AphrontDialogResponse' => 'AphrontResponse', @@ -459,19 +469,25 @@ phutil_register_library_map(array( 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSubscribeController' => 'DifferentialController', + 'DiffusionBranchTableView' => 'DiffusionView', 'DiffusionBrowseController' => 'DiffusionController', 'DiffusionBrowseFileController' => 'DiffusionController', - 'DiffusionBrowseTableView' => 'AphrontView', - 'DiffusionCommitChangeTableView' => 'AphrontView', + 'DiffusionBrowseTableView' => 'DiffusionView', + 'DiffusionCommitChangeTableView' => 'DiffusionView', 'DiffusionCommitController' => 'DiffusionController', 'DiffusionController' => 'PhabricatorController', + 'DiffusionGitBranchQuery' => 'DiffusionBranchQuery', 'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitHistoryQuery' => 'DiffusionHistoryQuery', 'DiffusionGitRequest' => 'DiffusionRequest', 'DiffusionHistoryController' => 'DiffusionController', - 'DiffusionHistoryTableView' => 'AphrontView', + 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHomeController' => 'DiffusionController', + 'DiffusionRepositoryController' => 'DiffusionController', + 'DiffusionSvnBrowseQuery' => 'DiffusionBrowseQuery', + 'DiffusionSvnHistoryQuery' => 'DiffusionHistoryQuery', + 'DiffusionView' => 'AphrontView', 'ManiphestController' => 'PhabricatorController', 'ManiphestDAO' => 'PhabricatorLiskDAO', 'ManiphestTask' => 'ManiphestDAO', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index aa07c7cbe1..62468c8d98 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -187,13 +187,14 @@ class AphrontDefaultApplicationConfiguration => 'DiffusionCommitController', '/diffusion/' => array( '$' => 'DiffusionHomeController', - '(?P[A-Z]+)' => array( - '/history/'. + '(?P[A-Z]+)/' => array( + '$' => 'DiffusionRepositoryController', + 'history/'. '(?P.*?)'. '(?:[;](?P[a-z0-9]+))?'. '$' => 'DiffusionHistoryController', - '/browse/'. + 'browse/'. '(?P.*?)'. '(?:[;](?P[a-z0-9]+))?'. '(?:[$](?P\d+))?'. diff --git a/src/applications/diffusion/controller/base/DiffusionController.php b/src/applications/diffusion/controller/base/DiffusionController.php index 5f6bc85bdb..43cd81b269 100644 --- a/src/applications/diffusion/controller/base/DiffusionController.php +++ b/src/applications/diffusion/controller/base/DiffusionController.php @@ -30,6 +30,10 @@ abstract class DiffusionController extends PhabricatorController { return $this; } + protected function getDiffusionRequest() { + return $this->diffusionRequest; + } + public function buildStandardPageResponse($view, array $data) { $page = $this->buildStandardPageView(); @@ -44,4 +48,183 @@ abstract class DiffusionController extends PhabricatorController { 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 = 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; + } + + $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'])) { + $crumb_list[] = $repository_name; + $crumbs->setCrumbs($crumb_list); + return $crumbs; + } + + $crumb_list[] = phutil_render_tag( + 'a', + array( + 'href' => "/diffusion/{$callsign}/", + ), + $repository_name); + + + if (empty($spec['view'])) { + $crumbs->setCrumbs($crumb_list); + return $crumbs; + } + + $view = $spec['view']; + + switch ($view) { + case 'history': + $view_name = 'History'; + break; + case 'browse': + $view_name = 'Browse'; + break; + } + + $path = null; + if (isset($spec['path'])) { + $path = $drequest->getPath(); + } + + $view_root_uri = "/diffusion/{$callsign}/{$view}/{$branch_uri}"; + $jump_href = $view_root_uri; + + $view_tail_uri = null; + $raw_commit = $drequest->getRawCommit(); + 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) { + $commit_link = DiffusionView::linkCommit( + $repository, + $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; + } + } diff --git a/src/applications/diffusion/controller/base/__init__.php b/src/applications/diffusion/controller/base/__init__.php index c68cb98500..d3298a471f 100644 --- a/src/applications/diffusion/controller/base/__init__.php +++ b/src/applications/diffusion/controller/base/__init__.php @@ -9,7 +9,11 @@ phutil_require_module('phabricator', 'aphront/response/webpage'); phutil_require_module('phabricator', 'applications/base/controller/base'); phutil_require_module('phabricator', 'applications/diffusion/request/base'); +phutil_require_module('phabricator', 'applications/diffusion/view/base'); +phutil_require_module('phabricator', 'view/layout/crumbs'); +phutil_require_module('phabricator', 'view/layout/sidenav'); +phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/diffusion/controller/browse/DiffusionBrowseController.php b/src/applications/diffusion/controller/browse/DiffusionBrowseController.php index 5d1af4babd..868aaa5cb6 100644 --- a/src/applications/diffusion/controller/browse/DiffusionBrowseController.php +++ b/src/applications/diffusion/controller/browse/DiffusionBrowseController.php @@ -26,6 +26,13 @@ class DiffusionBrowseController extends DiffusionController { $content = array(); + $content[] = $this->buildCrumbs( + array( + 'branch' => true, + 'path' => true, + 'view' => 'browse', + )); + if (!$results) { switch ($browse_query->getReasonForEmptyResultSet()) { @@ -69,19 +76,16 @@ class DiffusionBrowseController extends DiffusionController { $browse_table->setPaths($results); $browse_panel = new AphrontPanelView(); - $browse_panel->setHeader($drequest->getPath()); $browse_panel->appendChild($browse_table); $content[] = $browse_panel; - - // TODO: Branch table } - // TODO: Crumbs - // TODO: Side nav + $nav = $this->buildSideNav('browse', false); + $nav->appendChild($content); return $this->buildStandardPageResponse( - $content, + $nav, array( 'title' => basename($drequest->getPath()), )); diff --git a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php b/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php index 7dec1a0bae..148766f182 100644 --- a/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php +++ b/src/applications/diffusion/controller/file/DiffusionBrowseFileController.php @@ -19,6 +19,15 @@ class DiffusionBrowseFileController extends DiffusionController { public function processRequest() { + + $content = array(); + $content[] = $this->buildCrumbs( + array( + 'branch' => true, + 'path' => true, + 'view' => 'browse', + )); + $file_query = DiffusionFileContentQuery::newFromDiffusionRequest( $this->diffusionRequest); $file_content = $file_query->loadFileContent(); @@ -26,13 +35,19 @@ class DiffusionBrowseFileController extends DiffusionController { $corpus = phutil_render_tag( 'textarea', array( + 'style' => 'margin: 1em 2em; width: 90%; height: 80em;', ), phutil_escape_html($file_content->getCorpus())); + $content[] = $corpus; + // TODO: blame, color, line numbers, highlighting, etc etc + $nav = $this->buildSideNav('browse', true); + $nav->appendChild($content); + return $this->buildStandardPageResponse( - $corpus, + $nav, array( 'title' => 'Browse', )); diff --git a/src/applications/diffusion/controller/history/DiffusionHistoryController.php b/src/applications/diffusion/controller/history/DiffusionHistoryController.php index 3f5ee68690..f64e3e97e3 100644 --- a/src/applications/diffusion/controller/history/DiffusionHistoryController.php +++ b/src/applications/diffusion/controller/history/DiffusionHistoryController.php @@ -28,21 +28,30 @@ class DiffusionHistoryController extends DiffusionController { $content = array(); + $content[] = $this->buildCrumbs( + array( + 'branch' => true, + 'path' => true, + 'view' => 'history', + )); + $history_table = new DiffusionHistoryTableView(); $history_table->setDiffusionRequest($drequest); $history_table->setHistory($history); $history_panel = new AphrontPanelView(); - $history_panel->setHeader($drequest->getPath()); $history_panel->appendChild($history_table); $content[] = $history_panel; - // TODO: Crumbs - // TODO: Side nav + // TODO: Sometimes we do have a change view, we need to look at the most + // recent history entry to figure it out. + + $nav = $this->buildSideNav('history', false); + $nav->appendChild($content); return $this->buildStandardPageResponse( - $content, + $nav, array( 'title' => 'history', )); diff --git a/src/applications/diffusion/controller/home/DiffusionHomeController.php b/src/applications/diffusion/controller/home/DiffusionHomeController.php index 306719b2d9..9989cb3b66 100644 --- a/src/applications/diffusion/controller/home/DiffusionHomeController.php +++ b/src/applications/diffusion/controller/home/DiffusionHomeController.php @@ -49,7 +49,7 @@ class DiffusionHomeController extends DiffusionController { phutil_render_tag( 'a', array( - 'href' => '#', // TODO: Link + 'href' => '/diffusion/'.$repository->getCallsign().'/', ), phutil_escape_html($repository->getName())), $repository->getVersionControlSystem(), @@ -81,8 +81,13 @@ class DiffusionHomeController extends DiffusionController { $panel->setHeader('Browse Repositories'); $panel->appendChild($table); + $crumbs = $this->buildCrumbs(); + return $this->buildStandardPageResponse( - $panel, + array( + $crumbs, + $panel, + ), array( 'title' => 'Diffusion', )); diff --git a/src/applications/diffusion/controller/repository/DiffusionRepositoryController.php b/src/applications/diffusion/controller/repository/DiffusionRepositoryController.php new file mode 100644 index 0000000000..7b14ccdd24 --- /dev/null +++ b/src/applications/diffusion/controller/repository/DiffusionRepositoryController.php @@ -0,0 +1,79 @@ +diffusionRequest; + + $content = array(); + + $crumbs = $this->buildCrumbs(); + $content[] = $crumbs; + + $history_query = DiffusionHistoryQuery::newFromDiffusionRequest( + $drequest); + $history_query->setLimit(15); + + $history = $history_query->loadHistory(); + $history_table = new DiffusionHistoryTableView(); + $history_table->setDiffusionRequest($drequest); + $history_table->setHistory($history); + + $panel = new AphrontPanelView(); + $panel->setHeader('Recent Commits'); + $panel->appendChild($history_table); + + $content[] = $panel; + + $browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest); + $results = $browse_query->loadPaths(); + + $browse_table = new DiffusionBrowseTableView(); + $browse_table->setDiffusionRequest($drequest); + $browse_table->setPaths($results); + + $browse_panel = new AphrontPanelView(); + $browse_panel->setHeader('Browse Repository'); + $browse_panel->appendChild($browse_table); + + $content[] = $browse_panel; + + if ($drequest->getBranch() !== null) { + $branch_query = DiffusionBranchQuery::newFromDiffusionRequest($drequest); + $branches = $branch_query->loadBranches(); + + $branch_table = new DiffusionBranchTableView(); + $branch_table->setDiffusionRequest($drequest); + $branch_table->setBranches($branches); + + $branch_panel = new AphrontPanelView(); + $branch_panel->setHeader('Branches'); + $branch_panel->appendChild($branch_table); + + $content[] = $branch_panel; + } + + return $this->buildStandardPageResponse( + $content, + array( + 'title' => 'Diffusion', + )); + } + +} diff --git a/src/applications/diffusion/controller/repository/__init__.php b/src/applications/diffusion/controller/repository/__init__.php new file mode 100644 index 0000000000..6f5e15daaa --- /dev/null +++ b/src/applications/diffusion/controller/repository/__init__.php @@ -0,0 +1,19 @@ +name = $name; + return $this; + } + + public function getName() { + return $this->name; + } + + public function setHeadCommitIdentifier($head_commit_identifier) { + $this->headCommitIdentifier = $head_commit_identifier; + return $this; + } + + public function getHeadCommitIdentifier() { + return $this->headCommitIdentifier; + } + +} diff --git a/src/applications/diffusion/data/branch/__init__.php b/src/applications/diffusion/data/branch/__init__.php new file mode 100644 index 0000000000..43da675b4a --- /dev/null +++ b/src/applications/diffusion/data/branch/__init__.php @@ -0,0 +1,10 @@ +commit = $commit; + final public function setCommitIdentifier($commit) { + $this->commitIdentifier = $commit; return $this; } - final public function getCommit() { - return $this->commit; + final public function getCommitIdentifier() { + return $this->commitIdentifier; } diff --git a/src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php b/src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php new file mode 100644 index 0000000000..811916f0cd --- /dev/null +++ b/src/applications/diffusion/query/branch/base/DiffusionBranchQuery.php @@ -0,0 +1,57 @@ + + } + + final public static function newFromDiffusionRequest( + DiffusionRequest $request) { + + $repository = $request->getRepository(); + + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $class = 'DiffusionGitBranchQuery'; + break; + default: + throw new Exception("Unsupported VCS!"); + } + + PhutilSymbolLoader::loadClass($class); + $query = new $class(); + + $query->request = $request; + + return $query; + } + + final protected function getRequest() { + return $this->request; + } + + final public function loadBranches() { + return $this->executeQuery(); + } + + abstract protected function executeQuery(); +} diff --git a/src/applications/diffusion/query/branch/base/__init__.php b/src/applications/diffusion/query/branch/base/__init__.php new file mode 100644 index 0000000000..a03fa7e6a1 --- /dev/null +++ b/src/applications/diffusion/query/branch/base/__init__.php @@ -0,0 +1,14 @@ +getRequest(); + $repository = $drequest->getRepository(); + + $path = $drequest->getPath(); + $commit = $drequest->getCommit(); + + $local_path = $repository->getDetail('local-path'); + + list($stdout) = execx( + '(cd %s && git branch --verbose --no-abbrev)', + $local_path); + + $branches = array(); + + $lines = array_filter(explode("\n", $stdout)); + foreach ($lines as $line) { + $matches = null; + if (!preg_match('/^[ *] (\S+)\s+([a-z0-9]{40}) /', $line, $matches)) { + throw new Exception("Failed to parse {$line}!"); + } + $branch = new DiffusionBranchInformation(); + $branch->setName($matches[1]); + $branch->setHeadCommitIdentifier($matches[2]); + + $branches[] = $branch; + } + + return $branches; + } + +} diff --git a/src/applications/diffusion/query/branch/git/__init__.php b/src/applications/diffusion/query/branch/git/__init__.php new file mode 100644 index 0000000000..025d906a8b --- /dev/null +++ b/src/applications/diffusion/query/branch/git/__init__.php @@ -0,0 +1,15 @@ +getRepository(); switch ($repository->getVersionControlSystem()) { - case 'git': + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: // TODO: Verify local-path? $class = 'DiffusionGitBrowseQuery'; break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $class = 'DiffusionSvnBrowseQuery'; + break; default: throw new Exception("Unsupported VCS!"); } diff --git a/src/applications/diffusion/query/browse/base/__init__.php b/src/applications/diffusion/query/browse/base/__init__.php index 9bc1b90505..3e2ddb571f 100644 --- a/src/applications/diffusion/query/browse/base/__init__.php +++ b/src/applications/diffusion/query/browse/base/__init__.php @@ -6,6 +6,8 @@ +phutil_require_module('phabricator', 'applications/repository/constants/repositorytype'); + phutil_require_module('phutil', 'symbols'); diff --git a/src/applications/diffusion/query/browse/svn/DiffusionSvnBrowseQuery.php b/src/applications/diffusion/query/browse/svn/DiffusionSvnBrowseQuery.php new file mode 100644 index 0000000000..37da292afa --- /dev/null +++ b/src/applications/diffusion/query/browse/svn/DiffusionSvnBrowseQuery.php @@ -0,0 +1,93 @@ +getRequest(); + $repository = $drequest->getRepository(); + + $path = $drequest->getPath(); + $commit = $drequest->getCommit(); + + $path_normal = '/'.trim($path, '/'); + + $conn_r = $repository->establishConnection('r'); + + $paths = queryfx_all( + $conn_r, + 'SELECT id, path FROM %T WHERE path IN (%Ls)', + PhabricatorRepository::TABLE_PATH, + array($path_normal)); + $paths = ipull($paths, 'id', 'path'); + $path_id = $paths[$path_normal]; + + $index = queryfx_all( + $conn_r, + 'SELECT pathID, max(svnCommit) maxCommit FROM %T WHERE + repositoryID = %d AND parentID = %d + %Q GROUP BY pathID', + PhabricatorRepository::TABLE_FILESYSTEM, + $repository->getID(), + $path_id, + ''); + + if (!$index) { + // TODO: ! + return false; + } + + $sql = array(); + foreach ($index as $row) { + $sql[] = '('.(int)$row['pathID'].', '.(int)$row['maxCommit'].')'; + } + + $browse = queryfx_all( + $conn_r, + 'SELECT *, p.path pathName + FROM %T f JOIN %T p ON f.pathID = p.id + WHERE repositoryID = %d + AND parentID = %d + AND existed = 1 + AND (pathID, svnCommit) in (%Q) + ORDER BY pathName', + PhabricatorRepository::TABLE_FILESYSTEM, + PhabricatorRepository::TABLE_PATH, + $repository->getID(), + $path_id, + implode(', ', $sql)); + + $results = array(); + foreach ($browse as $file) { + + $file_path = $file['pathName']; + $file_path = ltrim(substr($file_path, strlen($path_normal)), '/'); + + $result = new DiffusionRepositoryPath(); + $result->setPath($file_path); +// $result->setHash($hash); + $result->setFileType($file['fileType']); +// $result->setFileSize($size); + + $results[] = $result; + } + + return $results; + } + +} diff --git a/src/applications/diffusion/query/browse/svn/__init__.php b/src/applications/diffusion/query/browse/svn/__init__.php new file mode 100644 index 0000000000..2f3932f527 --- /dev/null +++ b/src/applications/diffusion/query/browse/svn/__init__.php @@ -0,0 +1,17 @@ + @@ -30,9 +31,12 @@ abstract class DiffusionHistoryQuery { $repository = $request->getRepository(); switch ($repository->getVersionControlSystem()) { - case 'git': + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $class = 'DiffusionGitHistoryQuery'; break; + case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: + $class = 'DiffusionSvnHistoryQuery'; + break; default: throw new Exception("Unsupported VCS!"); } @@ -53,5 +57,14 @@ abstract class DiffusionHistoryQuery { return $this->executeQuery(); } + final public function setLimit($limit) { + $this->limit = $limit; + return $this; + } + + final public function getLimit() { + return $this->limit; + } + abstract protected function executeQuery(); } diff --git a/src/applications/diffusion/query/history/base/__init__.php b/src/applications/diffusion/query/history/base/__init__.php index df26090017..010bb2a494 100644 --- a/src/applications/diffusion/query/history/base/__init__.php +++ b/src/applications/diffusion/query/history/base/__init__.php @@ -6,6 +6,8 @@ +phutil_require_module('phabricator', 'applications/repository/constants/repositorytype'); + phutil_require_module('phutil', 'symbols'); diff --git a/src/applications/diffusion/query/history/git/DiffusionGitHistoryQuery.php b/src/applications/diffusion/query/history/git/DiffusionGitHistoryQuery.php index 7e6cbd7e8a..9226d98069 100644 --- a/src/applications/diffusion/query/history/git/DiffusionGitHistoryQuery.php +++ b/src/applications/diffusion/query/history/git/DiffusionGitHistoryQuery.php @@ -30,8 +30,8 @@ final class DiffusionGitHistoryQuery extends DiffusionHistoryQuery { list($stdout) = execx( '(cd %s && %s log '. - '-n %d '. '--skip=%d '. + '-n %d '. '-M '. '-C '. '-B '. @@ -43,8 +43,8 @@ final class DiffusionGitHistoryQuery extends DiffusionHistoryQuery { '%s -- %s)', $local_path, $git, - $limit = 100, $offset = 0, + $this->getLimit(), $commit, $path); @@ -56,7 +56,7 @@ final class DiffusionGitHistoryQuery extends DiffusionHistoryQuery { list($hash, $raw) = explode("\x1d", $commit); $item = new DiffusionPathChange(); - $item->setCommit($hash); + $item->setCommitIdentifier($hash); $history[] = $item; } diff --git a/src/applications/diffusion/query/history/svn/DiffusionSvnHistoryQuery.php b/src/applications/diffusion/query/history/svn/DiffusionSvnHistoryQuery.php new file mode 100644 index 0000000000..a95b588c8a --- /dev/null +++ b/src/applications/diffusion/query/history/svn/DiffusionSvnHistoryQuery.php @@ -0,0 +1,60 @@ +getRequest(); + + $repository = $drequest->getRepository(); + $path = $drequest->getPath(); + $commit = $drequest->getCommit(); + + $conn_r = $repository->establishConnection('r'); + + $paths = queryfx_all( + $conn_r, + 'SELECT id, path FROM %T WHERE path IN (%Ls)', + PhabricatorRepository::TABLE_PATH, + array('/'.trim($path, '/'))); + $paths = ipull($paths, 'id', 'path'); + $path_id = $paths['/'.trim($path, '/')]; + + $history_data = queryfx_all( + $conn_r, + 'SELECT * FROM %T WHERE repositoryID = %d AND pathID = %d + AND commitSequence <= %d + ORDER BY commitSequence DESC + LIMIT %d', + PhabricatorRepository::TABLE_PATHCHANGE, + $repository->getID(), + $path_id, + $commit ? $commit : 0x7FFFFFFF, + $this->getLimit()); + + $history = array(); + foreach ($history_data as $row) { + $item = new DiffusionPathChange(); + $item->setCommitIdentifier($row['commitID']); + $history[] = $item; + } + + return $history; + } + +} diff --git a/src/applications/diffusion/query/history/svn/__init__.php b/src/applications/diffusion/query/history/svn/__init__.php new file mode 100644 index 0000000000..c82a795dc9 --- /dev/null +++ b/src/applications/diffusion/query/history/svn/__init__.php @@ -0,0 +1,17 @@ +branch; } + final public function getRawCommit() { + return $this->commit; + } + + public function getCommitURIComponent($commit) { + return $commit; + } + + public function getBranchURIComponent($branch) { + return $branch; + } + } diff --git a/src/applications/diffusion/request/git/DiffusionGitRequest.php b/src/applications/diffusion/request/git/DiffusionGitRequest.php index ab00541dc0..f4c314eb94 100644 --- a/src/applications/diffusion/request/git/DiffusionGitRequest.php +++ b/src/applications/diffusion/request/git/DiffusionGitRequest.php @@ -27,6 +27,14 @@ class DiffusionGitRequest extends DiffusionRequest { $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) { @@ -96,6 +104,10 @@ class DiffusionGitRequest extends DiffusionRequest { return $this->getBranch(); } + public function getBranchURIComponent($branch) { + return $this->encodeBranchName($branch).'/'; + } + private function decodeBranchName($branch) { return str_replace(':', '/', $branch); } diff --git a/src/applications/diffusion/view/base/DiffusionView.php b/src/applications/diffusion/view/base/DiffusionView.php new file mode 100644 index 0000000000..72783cccf6 --- /dev/null +++ b/src/applications/diffusion/view/base/DiffusionView.php @@ -0,0 +1,109 @@ +diffusionRequest = $request; + return $this; + } + + final public function getDiffusionRequest() { + return $this->diffusionRequest; + } + + final public function linkHistory($path) { + $drequest = $this->getDiffusionRequest(); + + if ($drequest->getRawCommit()) { + $commit = ';'.$drequest->getCommitURIComponent($drequest->getRawCommit()); + } else { + $commit = null; + } + + $repository = $drequest->getRepository(); + $callsign = $repository->getCallsign(); + + $branch = $drequest->getBranchURIComponent($drequest->getBranch()); + $path = $branch.$path; + + $text = 'History'; + + return phutil_render_tag( + 'a', + array( + 'href' => "/diffusion/{$callsign}/history/{$path}{$commit}", + ), + $text); + } + + final public function linkBrowse($path, array $details = array()) { + $drequest = $this->getDiffusionRequest(); + + $raw_commit = idx($details, 'commit', $drequest->getRawCommit()); + if ($raw_commit) { + $commit = ';'.$drequest->getCommitURIComponent($raw_commit); + } else { + $commit = null; + } + + $repository = $drequest->getRepository(); + $callsign = $repository->getCallsign(); + + $branch = $drequest->getBranchURIComponent($drequest->getBranch()); + $path = $branch.$path; + + if (isset($details['text'])) { + $text = phutil_escape_html($details['text']); + } else { + $text = 'Browse'; + } + + return phutil_render_tag( + 'a', + array( + 'href' => "/diffusion/{$callsign}/browse/{$path}{$commit}", + ), + $text); + } + + final public static function linkCommit($repository, $commit) { + + switch ($repository->getVersionControlSystem()) { + case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: + $commit_name = substr($commit, 0, 7); + break; + default: + $commit_name = $commit; + break; + } + + $callsign = $repository->getCallsign(); + $commit_name = "r{$callsign}{$commit_name}"; + + return phutil_render_tag( + 'a', + array( + 'href' => "/r{$callsign}{$commit}", + ), + $commit_name); + } + +} diff --git a/src/applications/diffusion/view/base/__init__.php b/src/applications/diffusion/view/base/__init__.php new file mode 100644 index 0000000000..4a1c56d3a7 --- /dev/null +++ b/src/applications/diffusion/view/base/__init__.php @@ -0,0 +1,16 @@ +branches = $branches; + return $this; + } + + public function render() { + $drequest = $this->getDiffusionRequest(); + $current_branch = $drequest->getBranch(); + + $rows = array(); + $rowc = array(); + foreach ($this->branches as $branch) { + $rows[] = array( + phutil_escape_html($branch->getName()), // TODO: link + self::linkCommit( + $drequest->getRepository(), + $branch->getHeadCommitIdentifier()), + // TODO: etc etc + ); + if ($branch->getName() == $current_branch) { + $rowc[] = 'highlighted'; + } else { + $rowc[] = null; + } + } + + $view = new AphrontTableView($rows); + $view->setHeaders( + array( + 'Branch', + 'Head', + )); + $view->setColumnClasses( + array( + 'wide', + )); + $view->setRowClasses($rowc); + return $view->render(); + } + +} diff --git a/src/applications/diffusion/view/branchtable/__init__.php b/src/applications/diffusion/view/branchtable/__init__.php new file mode 100644 index 0000000000..0fa1d5c6e5 --- /dev/null +++ b/src/applications/diffusion/view/branchtable/__init__.php @@ -0,0 +1,15 @@ +request = $request; - return $this; - } - public function setPaths(array $paths) { $this->paths = $paths; return $this; } public function render() { + $request = $this->getDiffusionRequest(); + + $base_path = trim($request->getPath(), '/'); + if ($base_path) { + $base_path = $base_path.'/'; + } + $rows = array(); foreach ($this->paths as $path) { + + if ($path->getFileType() == DifferentialChangeType::FILE_DIRECTORY) { + $browse_text = $path->getPath().'/'; + $dir_slash = '/'; + } else { + $browse_text = $path->getPath(); + $dir_slash = null; + } + $rows[] = array( - phutil_escape_html($path->getPath()), // TODO: link - // TODO: etc etc + $this->linkHistory($base_path.$path->getPath().$dir_slash), + $this->linkBrowse( + $base_path.$path->getPath().$dir_slash, + array( + 'text' => $browse_text, + )), ); } $view = new AphrontTableView($rows); $view->setHeaders( array( + 'History', 'Path', )); + $view->setColumnClasses( + array( + '', + 'wide pri', + )); return $view->render(); } diff --git a/src/applications/diffusion/view/browsetable/__init__.php b/src/applications/diffusion/view/browsetable/__init__.php index e6361bcfc8..12e1f538ef 100644 --- a/src/applications/diffusion/view/browsetable/__init__.php +++ b/src/applications/diffusion/view/browsetable/__init__.php @@ -6,10 +6,9 @@ -phutil_require_module('phabricator', 'view/base'); +phutil_require_module('phabricator', 'applications/differential/constants/changetype'); +phutil_require_module('phabricator', 'applications/diffusion/view/base'); phutil_require_module('phabricator', 'view/control/table'); -phutil_require_module('phutil', 'markup'); - phutil_require_source('DiffusionBrowseTableView.php'); diff --git a/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php b/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php index 566cb4c5f5..863455aec6 100644 --- a/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php +++ b/src/applications/diffusion/view/commitchangetable/DiffusionCommitChangeTableView.php @@ -16,16 +16,10 @@ * limitations under the License. */ -final class DiffusionCommitChangeTableView extends AphrontView { +final class DiffusionCommitChangeTableView extends DiffusionView { - private $request; private $pathChanges; - public function setDiffusionRequest(DiffusionRequest $request) { - $this->request = $request; - return $this; - } - public function setPathChanges(array $path_changes) { $this->pathChanges = $path_changes; return $this; diff --git a/src/applications/diffusion/view/commitchangetable/__init__.php b/src/applications/diffusion/view/commitchangetable/__init__.php index 38dfa02082..a8d32cb9ac 100644 --- a/src/applications/diffusion/view/commitchangetable/__init__.php +++ b/src/applications/diffusion/view/commitchangetable/__init__.php @@ -6,7 +6,7 @@ -phutil_require_module('phabricator', 'view/base'); +phutil_require_module('phabricator', 'applications/diffusion/view/base'); phutil_require_module('phabricator', 'view/control/table'); diff --git a/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php b/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php index 3f05c6d7ce..c1960a7403 100644 --- a/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php +++ b/src/applications/diffusion/view/historytable/DiffusionHistoryTableView.php @@ -16,26 +16,33 @@ * limitations under the License. */ -final class DiffusionHistoryTableView extends AphrontView { +final class DiffusionHistoryTableView extends DiffusionView { - private $request; private $history; - public function setDiffusionRequest(DiffusionRequest $request) { - $this->request = $request; - return $this; - } - public function setHistory(array $history) { $this->history = $history; return $this; } public function render() { + $drequest = $this->getDiffusionRequest(); + $rows = array(); foreach ($this->history as $history) { $rows[] = array( - phutil_escape_html($history->getCommit()), // TODO: link + $this->linkBrowse( + $drequest->getPath(), + array( + 'commit' => $history->getCommitIdentifier(), + )), + self::linkCommit( + $drequest->getRepository(), + $history->getCommitIdentifier()), + '?', + '?', + '', + '', // TODO: etc etc ); } @@ -43,7 +50,21 @@ final class DiffusionHistoryTableView extends AphrontView { $view = new AphrontTableView($rows); $view->setHeaders( array( + 'Browse', 'Commit', + 'Change', + 'Date', + 'Author', + 'Details', + )); + $view->setColumnClasses( + array( + '', + 'n', + '', + '', + '', + 'wide wrap', )); return $view->render(); } diff --git a/src/applications/diffusion/view/historytable/__init__.php b/src/applications/diffusion/view/historytable/__init__.php index e53ae0b476..f6e0c07164 100644 --- a/src/applications/diffusion/view/historytable/__init__.php +++ b/src/applications/diffusion/view/historytable/__init__.php @@ -6,10 +6,8 @@ -phutil_require_module('phabricator', 'view/base'); +phutil_require_module('phabricator', 'applications/diffusion/view/base'); phutil_require_module('phabricator', 'view/control/table'); -phutil_require_module('phutil', 'markup'); - phutil_require_source('DiffusionHistoryTableView.php'); diff --git a/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php b/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php index c6e6763c4a..b1a620f55e 100644 --- a/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php +++ b/src/applications/repository/worker/commitchangeparser/svn/PhabricatorRepositorySvnCommitChangeParserWorker.php @@ -429,6 +429,12 @@ class PhabricatorRepositorySvnCommitChangeParserWorker } } + if ($effect['rawPath'] == '/') { + // Don't bother writing the CHILD events on '/' to the filesystem + // table; in particular, it doesn't have a meaningful parentID. + continue; + } + $existed = !DifferentialChangeType::isDeleteChangeType($type); $sql[] = qsprintf( @@ -607,9 +613,8 @@ class PhabricatorRepositorySvnCommitChangeParserWorker } private function getParentPath($path) { - $path = rtrim('/', $path); + $path = rtrim($path, '/'); $path = dirname($path); - $path = rtrim('/', $path); if (!$path) { $path = '/'; } diff --git a/src/view/base/AphrontView.php b/src/view/base/AphrontView.php index 263f56b98d..99196f28e1 100755 --- a/src/view/base/AphrontView.php +++ b/src/view/base/AphrontView.php @@ -28,18 +28,18 @@ abstract class AphrontView { final protected function renderChildren() { $out = array(); foreach ($this->children as $child) { - $out[] = $this->renderChild($child); + $out[] = $this->renderSingleView($child); } return implode('', $out); } - private function renderChild($child) { + final protected function renderSingleView($child) { if ($child instanceof AphrontView) { return $child->render(); } else if (is_array($child)) { $out = array(); foreach ($child as $element) { - $out[] = $this->renderChild($element); + $out[] = $this->renderSingleView($element); } return implode('', $out); } else { diff --git a/src/view/layout/crumbs/AphrontCrumbsView.php b/src/view/layout/crumbs/AphrontCrumbsView.php new file mode 100644 index 0000000000..7085651519 --- /dev/null +++ b/src/view/layout/crumbs/AphrontCrumbsView.php @@ -0,0 +1,50 @@ +crumbs = $crumbs; + return; + } + + public function render() { + + require_celerity_resource('aphront-crumbs-view-css'); + + $out = array(); + foreach ($this->crumbs as $crumb) { + $out[] = $this->renderSingleView($crumb); + } + $out = implode( + ''. + "\xC2\xBB". + '', + $out); + + return + '
'. + '
'. + $out. + '
'. + '
'; + } + +} diff --git a/src/view/layout/crumbs/__init__.php b/src/view/layout/crumbs/__init__.php new file mode 100644 index 0000000000..53d523045d --- /dev/null +++ b/src/view/layout/crumbs/__init__.php @@ -0,0 +1,13 @@ +