From 0d8bac97aef554bf4d9f203e07167ad379dd090e Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 7 Mar 2011 17:25:47 -0800 Subject: [PATCH] Diffusion: basic browse view Summary: Synthesizes elements of Diffusion's browse view, Confusion's git support and Phabricator's repository infrastructure to provide a basic browse view for Phabricator Diffusion. This is basically a straight port of Confusion but uses Phabricator's Repository object and uses a real data object instead of arrays. Test Plan: Browsed Javelin in Phabricator at a very basic level. Reviewed By: jwilson Reviewers: aran, jwilson CC: jwilson, epriestley Differential Revision: 58 --- conf/default.conf.php | 6 ++ src/__phutil_library_map__.php | 8 ++ ...AphrontDefaultApplicationConfiguration.php | 5 ++ .../controller/base/DiffusionController.php | 10 +++ .../diffusion/controller/base/__init__.php | 1 + .../browse/DiffusionBrowseController.php | 73 +++++++++++++++++ .../diffusion/controller/browse/__init__.php | 17 ++++ .../DiffusionRepositoryPath.php | 62 +++++++++++++++ .../data/repositorypath/__init__.php | 10 +++ .../browse/base/DiffusionBrowseQuery.php | 79 +++++++++++++++++++ .../diffusion/query/browse/base/__init__.php | 12 +++ .../browse/git/DiffusionGitBrowseQuery.php | 79 +++++++++++++++++++ .../diffusion/query/browse/git/__init__.php | 18 +++++ .../browsetable/DiffusionBrowseTableView.php | 63 +++++++++++++++ .../diffusion/view/browsetable/__init__.php | 15 ++++ 15 files changed, 458 insertions(+) create mode 100644 src/applications/diffusion/controller/browse/DiffusionBrowseController.php create mode 100644 src/applications/diffusion/controller/browse/__init__.php create mode 100644 src/applications/diffusion/data/repositorypath/DiffusionRepositoryPath.php create mode 100644 src/applications/diffusion/data/repositorypath/__init__.php create mode 100644 src/applications/diffusion/query/browse/base/DiffusionBrowseQuery.php create mode 100644 src/applications/diffusion/query/browse/base/__init__.php create mode 100644 src/applications/diffusion/query/browse/git/DiffusionGitBrowseQuery.php create mode 100644 src/applications/diffusion/query/browse/git/__init__.php create mode 100644 src/applications/diffusion/view/browsetable/DiffusionBrowseTableView.php create mode 100644 src/applications/diffusion/view/browsetable/__init__.php diff --git a/conf/default.conf.php b/conf/default.conf.php index 07f397463a..bc4f589644 100644 --- a/conf/default.conf.php +++ b/conf/default.conf.php @@ -286,4 +286,10 @@ return array( 'controller.oauth-registration' => 'PhabricatorOAuthDefaultRegistrationController', + + + // Path to the 'git' binary to execute when running git commands. By default + // this should work fine, but if you have a weird environment you may need + // to set it explicitly (e.g., apache may not have it in its PATH). + 'git.path' => 'git', ); diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 6b33581438..929cef998b 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -142,8 +142,13 @@ phutil_register_library_map(array( 'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview', 'DifferentialSubscribeController' => 'applications/differential/controller/subscribe', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', + 'DiffusionBrowseController' => 'applications/diffusion/controller/browse', + 'DiffusionBrowseQuery' => 'applications/diffusion/query/browse/base', + 'DiffusionBrowseTableView' => 'applications/diffusion/view/browsetable', 'DiffusionController' => 'applications/diffusion/controller/base', + 'DiffusionGitBrowseQuery' => 'applications/diffusion/query/browse/git', 'DiffusionHomeController' => 'applications/diffusion/controller/home', + 'DiffusionRepositoryPath' => 'applications/diffusion/data/repositorypath', 'Javelin' => 'infrastructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', 'ManiphestController' => 'applications/maniphest/controller/base', @@ -422,7 +427,10 @@ phutil_register_library_map(array( 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSubscribeController' => 'DifferentialController', + 'DiffusionBrowseController' => 'DiffusionController', + 'DiffusionBrowseTableView' => 'AphrontView', 'DiffusionController' => 'PhabricatorController', + 'DiffusionGitBrowseQuery' => 'DiffusionBrowseQuery', 'DiffusionHomeController' => 'DiffusionController', 'ManiphestController' => 'PhabricatorController', 'ManiphestDAO' => 'PhabricatorLiskDAO', diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 822fec4af6..cc2ac4d24b 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -185,6 +185,11 @@ class AphrontDefaultApplicationConfiguration '/diffusion/' => array( '$' => 'DiffusionHomeController', + '(?P[A-Z]+)/browse/'. + '(?P.*?)'. + '(?:[;](?P[a-z0-9]+))?'. + '(?:[$](?P\d+))?$' + => 'DiffusionBrowseController', ), ); diff --git a/src/applications/diffusion/controller/base/DiffusionController.php b/src/applications/diffusion/controller/base/DiffusionController.php index 3e07b1230b..c0d46bf25c 100644 --- a/src/applications/diffusion/controller/base/DiffusionController.php +++ b/src/applications/diffusion/controller/base/DiffusionController.php @@ -32,4 +32,14 @@ abstract class DiffusionController extends PhabricatorController { return $response->setContent($page->render()); } + protected function loadRepositoryByCallsign($callsign) { + $repository = id(new PhabricatorRepository())->loadOneWhere( + 'callsign = %s', + $callsign); + if (!$repository) { + throw new Exception("No such repository '{$callsign}'."); + } + return $repository; + } + } diff --git a/src/applications/diffusion/controller/base/__init__.php b/src/applications/diffusion/controller/base/__init__.php index cf7b058332..22786d371f 100644 --- a/src/applications/diffusion/controller/base/__init__.php +++ b/src/applications/diffusion/controller/base/__init__.php @@ -8,6 +8,7 @@ phutil_require_module('phabricator', 'aphront/response/webpage'); phutil_require_module('phabricator', 'applications/base/controller/base'); +phutil_require_module('phabricator', 'applications/repository/storage/repository'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/diffusion/controller/browse/DiffusionBrowseController.php b/src/applications/diffusion/controller/browse/DiffusionBrowseController.php new file mode 100644 index 0000000000..11c4abf5a1 --- /dev/null +++ b/src/applications/diffusion/controller/browse/DiffusionBrowseController.php @@ -0,0 +1,73 @@ +callsign = $data['callsign']; + $this->path = rtrim($data['path'], '/'); + + $this->line = idx($data, 'line'); + $this->commit = idx($data, 'commit'); + } + + public function processRequest() { + $repository = $this->loadRepositoryByCallsign($this->callsign); + + $browse_data = DiffusionBrowseQuery::newFromRepository( + $repository, + $this->path, + $this->commit); + $results = $browse_data->loadPaths(); + + if (!$results) { + // TODO: useful output (path does not exist / never existed), or file + // data. + throw new Exception("No browse results."); + } else { + $browse_table = new DiffusionBrowseTableView(); + $browse_table->setRepository($repository); + $browse_table->setPaths($results); + $browse_table->setRoot($this->path); + $browse_table->setCommit($this->commit); + + $browse_panel = new AphrontPanelView(); + $browse_panel->setHeader($this->path); + $browse_panel->appendChild($browse_table); + + // TODO: Branch table + } + + // TODO: Crumbs + // TODO: Side nav + + return $this->buildStandardPageResponse( + $browse_panel, + array( + 'title' => basename($this->path), + )); + } + +} diff --git a/src/applications/diffusion/controller/browse/__init__.php b/src/applications/diffusion/controller/browse/__init__.php new file mode 100644 index 0000000000..1335823c1d --- /dev/null +++ b/src/applications/diffusion/controller/browse/__init__.php @@ -0,0 +1,17 @@ +path = $path; + return $this; + } + + final public function getPath() { + return $this->path; + } + + final public function setHash($hash) { + $this->hash = $hash; + return $this; + } + + final public function getHash() { + return $this->hash; + } + + final public function setFileType($file_type) { + $this->fileType = $file_type; + return $this; + } + + final public function getFileType() { + return $this->fileType; + } + + final public function setFileSize($file_size) { + $this->fileSize = $file_size; + return $this; + } + + final public function getFileSize() { + return $this->fileSize; + } + +} diff --git a/src/applications/diffusion/data/repositorypath/__init__.php b/src/applications/diffusion/data/repositorypath/__init__.php new file mode 100644 index 0000000000..54529b3510 --- /dev/null +++ b/src/applications/diffusion/data/repositorypath/__init__.php @@ -0,0 +1,10 @@ + + } + + final public static function newFromRepository( + PhabricatorRepository $repository, + $path = '/', + $commit = null) { + + switch ($repository->getVersionControlSystem()) { + case 'git': + // TODO: Verify local-path? + $class = 'DiffusionGitBrowseQuery'; + break; + default: + throw new Exception("Unsupported VCS!"); + } + + PhutilSymbolLoader::loadClass($class); + $query = new $class(); + + $query->repository = $repository; + $query->path = $path; + $query->commit = $commit; + + return $query; + } + + final protected function getRepository() { + return $this->repository; + } + + final protected function getPath() { + return $this->path; + } + + final protected function getCommit() { + return $this->commit; + } + + final public function getReasonForEmptyResultSet() { + return $this->reason; + } + + final public function loadPaths() { + return $this->executeQuery(); + } + + abstract protected function executeQuery(); +} diff --git a/src/applications/diffusion/query/browse/base/__init__.php b/src/applications/diffusion/query/browse/base/__init__.php new file mode 100644 index 0000000000..9bc1b90505 --- /dev/null +++ b/src/applications/diffusion/query/browse/base/__init__.php @@ -0,0 +1,12 @@ +getRepository(); + $path = $this->getPath(); + $commit = nonempty($this->getCommit(), 'HEAD'); + + $local_path = $repository->getDetail('local-path'); + + $git = PhabricatorEnv::getEnvConfig('git.path'); + + try { + list($stdout) = execx( + "(cd %s && %s cat-file -t %s:%s)", + $local_path, + $git, + $commit, + $path); + } catch (CommandException $e) { + if (preg_match('/^fatal: Not a valid object name/', $e->getStderr())) { + $this->reason = self::REASON_IS_NONEXISTENT; + return array(); + } else { + throw $e; + } + } + + if (trim($stdout) == 'blob') { + $this->reason = self::REASON_IS_FILE; + return array(); + } + + list($stdout) = execx( + "(cd %s && %s ls-tree -l %s:%s)", + $local_path, + $git, + $commit, + $path); + + $results = array(); + foreach (explode("\n", rtrim($stdout)) as $line) { + list($mode, $type, $hash, $size, $name) = preg_split('/\s+/', $line); + if ($type == 'tree') { + $file_type = DifferentialChangeType::FILE_DIRECTORY; + } else { + $file_type = DifferentialChangeType::FILE_NORMAL; + } + + $result = new DiffusionRepositoryPath(); + $result->setPath($name); + $result->setHash($hash); + $result->setFileType($file_type); + $result->setFileSize($size); + + $results[] = $result; + } + + return $results; + } + +} diff --git a/src/applications/diffusion/query/browse/git/__init__.php b/src/applications/diffusion/query/browse/git/__init__.php new file mode 100644 index 0000000000..ef4ef03fdf --- /dev/null +++ b/src/applications/diffusion/query/browse/git/__init__.php @@ -0,0 +1,18 @@ +repository = $repository; + return $this; + } + + public function setPaths(array $paths) { + $this->paths = $paths; + return $this; + } + + public function setRoot($root) { + $this->root = $root; + return $this; + } + + public function setCommit($commit) { + $this->commit = $commit; + return $this; + } + + public function render() { + $rows = array(); + foreach ($this->paths as $path) { + $rows[] = array( + phutil_escape_html($path->getPath()), // TODO: link + // TODO: etc etc + ); + } + + $view = new AphrontTableView($rows); + $view->setHeaders( + array( + 'Path', + )); + return $view->render(); + } + +} diff --git a/src/applications/diffusion/view/browsetable/__init__.php b/src/applications/diffusion/view/browsetable/__init__.php new file mode 100644 index 0000000000..e6361bcfc8 --- /dev/null +++ b/src/applications/diffusion/view/browsetable/__init__.php @@ -0,0 +1,15 @@ +