3 abstract class DiffusionController
extends PhabricatorController
{
5 private $diffusionRequest;
7 protected function getDiffusionRequest() {
8 if (!$this->diffusionRequest
) {
9 throw new PhutilInvalidStateException('loadDiffusionContext');
11 return $this->diffusionRequest
;
14 protected function hasDiffusionRequest() {
15 return (bool)$this->diffusionRequest
;
18 public function willBeginExecution() {
19 $request = $this->getRequest();
21 // Check if this is a VCS request, e.g. from "git clone", "hg clone", or
22 // "svn checkout". If it is, we jump off into repository serving code to
23 // process the request.
25 $serve_controller = new DiffusionServeController();
26 if ($serve_controller->isVCSRequest($request)) {
27 return $this->delegateToController($serve_controller);
30 return parent
::willBeginExecution();
33 protected function loadDiffusionContextForEdit() {
34 return $this->loadContext(
40 protected function loadDiffusionContext() {
41 return $this->loadContext(array());
44 private function loadContext(array $options) {
45 $request = $this->getRequest();
46 $viewer = $this->getViewer();
47 require_celerity_resource('diffusion-repository-css');
49 $identifier = $this->getRepositoryIdentifierFromRequest($request);
51 $params = $options +
array(
52 'repository' => $identifier,
54 'blob' => $this->getDiffusionBlobFromRequest($request),
55 'commit' => $request->getURIData('commit'),
56 'path' => $request->getURIData('path'),
57 'line' => $request->getURIData('line'),
58 'branch' => $request->getURIData('branch'),
59 'lint' => $request->getStr('lint'),
62 $drequest = DiffusionRequest
::newFromDictionary($params);
65 return new Aphront404Response();
68 // If the client is making a request like "/diffusion/1/...", but the
69 // repository has a different canonical path like "/diffusion/XYZ/...",
70 // redirect them to the canonical path.
72 // Skip this redirect if the request is an AJAX request, like the requests
73 // that Owners makes to complete and validate paths.
75 if (!$request->isAjax()) {
76 $request_path = $request->getPath();
77 $repository = $drequest->getRepository();
79 $canonical_path = $repository->getCanonicalPath($request_path);
80 if ($canonical_path !== null) {
81 if ($canonical_path != $request_path) {
82 return id(new AphrontRedirectResponse())->setURI($canonical_path);
87 $this->diffusionRequest
= $drequest;
92 protected function getDiffusionBlobFromRequest(AphrontRequest
$request) {
93 return $request->getURIData('dblob');
96 protected function getRepositoryIdentifierFromRequest(
97 AphrontRequest
$request) {
99 $short_name = $request->getURIData('repositoryShortName');
100 if ($short_name !== null && strlen($short_name)) {
101 // If the short name ends in ".git", ignore it.
102 $short_name = preg_replace('/\\.git\z/', '', $short_name);
106 $identifier = $request->getURIData('repositoryCallsign');
107 if ($identifier !== null && strlen($identifier)) {
111 $id = $request->getURIData('repositoryID');
112 if ($id !== null && strlen($id)) {
119 public function buildCrumbs(array $spec = array()) {
120 $crumbs = $this->buildApplicationCrumbs();
121 $crumb_list = $this->buildCrumbList($spec);
122 foreach ($crumb_list as $crumb) {
123 $crumbs->addCrumb($crumb);
128 private function buildCrumbList(array $spec = array()) {
130 $spec = $spec +
array(
137 $crumb_list = array();
139 // On the home page, we don't have a DiffusionRequest.
140 if ($this->hasDiffusionRequest()) {
141 $drequest = $this->getDiffusionRequest();
142 $repository = $drequest->getRepository();
152 $repository_name = $repository->getName();
154 if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) {
155 $branch_name = $drequest->getBranch();
156 if (strlen($branch_name)) {
157 $repository_name .= ' ('.$branch_name.')';
161 $crumb = id(new PHUICrumbView())
162 ->setName($repository_name);
163 if (!$spec['view'] && !$spec['commit'] &&
164 !$spec['tags'] && !$spec['branches']) {
165 $crumb_list[] = $crumb;
169 $drequest->generateURI(
171 'action' => 'branch',
174 $crumb_list[] = $crumb;
176 $stable_commit = $drequest->getStableCommit();
177 $commit_name = $repository->formatCommitName($stable_commit, $local = true);
178 $commit_uri = $repository->getCommitURI($stable_commit);
181 $crumb = new PHUICrumbView();
182 if ($spec['commit']) {
183 $crumb->setName(pht('Tags for %s', $commit_name));
184 $crumb->setHref($commit_uri);
186 $crumb->setName(pht('Tags'));
188 $crumb_list[] = $crumb;
192 if ($spec['branches']) {
193 $crumb = id(new PHUICrumbView())
194 ->setName(pht('Branches'));
195 $crumb_list[] = $crumb;
199 if ($spec['commit']) {
200 $crumb = id(new PHUICrumbView())
201 ->setName($commit_name);
202 $crumb_list[] = $crumb;
206 $crumb = new PHUICrumbView();
207 $view = $spec['view'];
211 $view_name = pht('History');
214 $view_name = pht('Browse');
217 $view_name = pht('Lint');
220 $view_name = pht('Change');
223 $view_name = pht('Compare');
227 $crumb = id(new PHUICrumbView())
228 ->setName($view_name);
230 $crumb_list[] = $crumb;
234 protected function callConduitWithDiffusionRequest(
236 array $params = array()) {
238 $user = $this->getRequest()->getUser();
239 $drequest = $this->getDiffusionRequest();
241 return DiffusionQuery
::callConduitWithDiffusionRequest(
248 protected function callConduitMethod($method, array $params = array()) {
249 $user = $this->getViewer();
250 $drequest = $this->getDiffusionRequest();
252 return DiffusionQuery
::callConduitWithDiffusionRequest(
260 protected function getRepositoryControllerURI(
261 PhabricatorRepository
$repository,
263 return $repository->getPathURI($path);
266 protected function renderPathLinks(DiffusionRequest
$drequest, $action) {
267 $path = $drequest->getPath();
268 $path_parts = array();
269 if ($path !== null && strlen($path)) {
270 $path_parts = array_filter(explode('/', trim($path, '/')));
273 $divider = phutil_tag(
276 'class' => 'phui-header-divider',
282 $links[] = phutil_tag(
285 'href' => $drequest->generateURI(
291 $drequest->getRepository()->getDisplayName());
294 $last_key = last_key($path_parts);
295 foreach ($path_parts as $key => $part) {
297 if ($key === $last_key) {
300 $links[] = phutil_tag(
303 'href' => $drequest->generateURI(
306 'path' => $accum.'/',
314 $links[] = $drequest->getRepository()->getDisplayName();
321 protected function renderStatusMessage($title, $body) {
322 return id(new PHUIInfoView())
323 ->setSeverity(PHUIInfoView
::SEVERITY_NOTICE
)
326 ->appendChild($body);
329 protected function renderCommitHashTag(DiffusionRequest
$drequest) {
330 $stable_commit = $drequest->getStableCommit();
331 $commit = phutil_tag(
334 'href' => $drequest->generateURI(
336 'action' => 'commit',
337 'commit' => $stable_commit,
340 $drequest->getRepository()->formatCommitName($stable_commit, true));
342 $tag = id(new PHUITagView())
344 ->setColor(PHUITagView
::COLOR_INDIGO
)
345 ->setBorder(PHUITagView
::BORDER_NONE
)
346 ->setType(PHUITagView
::TYPE_SHADE
);
351 protected function renderBranchTag(DiffusionRequest
$drequest) {
352 $branch = $drequest->getBranch();
353 $branch = id(new PhutilUTF8StringTruncator())
354 ->setMaximumGlyphs(24)
355 ->truncateString($branch);
357 $tag = id(new PHUITagView())
359 ->setColor(PHUITagView
::COLOR_INDIGO
)
360 ->setBorder(PHUITagView
::BORDER_NONE
)
361 ->setType(PHUITagView
::TYPE_OUTLINE
)
362 ->addClass('diffusion-header-branch-tag');
367 protected function renderSymbolicCommit(DiffusionRequest
$drequest) {
368 $symbolic_tag = $drequest->getSymbolicCommit();
369 $symbolic_tag = id(new PhutilUTF8StringTruncator())
370 ->setMaximumGlyphs(24)
371 ->truncateString($symbolic_tag);
373 $tag = id(new PHUITagView())
374 ->setName($symbolic_tag)
376 ->setColor(PHUITagView
::COLOR_INDIGO
)
377 ->setBorder(PHUITagView
::BORDER_NONE
)
378 ->setType(PHUITagView
::TYPE_SHADE
);
383 protected function renderDirectoryReadme(DiffusionBrowseResultSet
$browse) {
384 $readme_path = $browse->getReadmePath();
385 if ($readme_path === null) {
389 $drequest = $this->getDiffusionRequest();
390 $viewer = $this->getViewer();
391 $repository = $drequest->getRepository();
392 $repository_phid = $repository->getPHID();
393 $stable_commit = $drequest->getStableCommit();
395 $stable_commit_hash = PhabricatorHash
::digestForIndex($stable_commit);
396 $readme_path_hash = PhabricatorHash
::digestForIndex($readme_path);
398 $cache = PhabricatorCaches
::getMutableStructureCache();
399 $cache_key = "diffusion".
400 ".repository({$repository_phid})".
401 ".commit({$stable_commit_hash})".
402 ".readme({$readme_path_hash})";
404 $readme_cache = $cache->getKey($cache_key);
405 if (!$readme_cache) {
407 $result = $this->callConduitWithDiffusionRequest(
408 'diffusion.filecontentquery',
410 'path' => $readme_path,
411 'commit' => $drequest->getStableCommit(),
413 } catch (Exception
$ex) {
417 $file_phid = $result['filePHID'];
422 $file = id(new PhabricatorFileQuery())
424 ->withPHIDs(array($file_phid))
430 $corpus = $file->loadFileData();
432 $readme_cache = array(
436 $cache->setKey($cache_key, $readme_cache);
439 $readme_corpus = $readme_cache['corpus'];
440 if (!strlen($readme_corpus)) {
444 return id(new DiffusionReadmeView())
445 ->setUser($this->getViewer())
446 ->setPath($readme_path)
447 ->setContent($readme_corpus);
450 protected function renderSearchForm($path = '/') {
451 $drequest = $this->getDiffusionRequest();
452 $viewer = $this->getViewer();
453 switch ($drequest->getRepository()->getVersionControlSystem()) {
454 case PhabricatorRepositoryType
::REPOSITORY_TYPE_SVN
:
458 $search_term = $this->getRequest()->getStr('grep');
459 require_celerity_resource('diffusion-icons-css');
460 require_celerity_resource('diffusion-css');
462 $href = $drequest->generateURI(array(
463 'action' => 'browse',
471 'id' => 'diffusion-search-input',
473 'class' => 'diffusion-search-input',
474 'sigil' => 'diffusion-search-input',
475 'placeholder' => pht('Pattern Search'),
476 'value' => $search_term,
479 $form = phabricator_form(
484 'sigil' => 'diffusion-search-form',
485 'class' => 'diffusion-search-form',
486 'id' => 'diffusion-search-form',
492 $form_view = phutil_tag(
495 'class' => 'diffusion-search-form-view',
502 protected function buildTabsView($key) {
503 $drequest = $this->getDiffusionRequest();
504 $repository = $drequest->getRepository();
506 $view = new PHUIListView();
509 id(new PHUIListItemView())
511 ->setName(pht('Code'))
513 ->setHref($drequest->generateURI(
515 'action' => 'browse',
517 ->setSelected($key == 'code'));
519 if (!$repository->isSVN()) {
521 id(new PHUIListItemView())
523 ->setName(pht('Branches'))
524 ->setIcon('fa-code-fork')
525 ->setHref($drequest->generateURI(
527 'action' => 'branches',
529 ->setSelected($key == 'branch'));
532 if (!$repository->isSVN()) {
534 id(new PHUIListItemView())
536 ->setName(pht('Tags'))
538 ->setHref($drequest->generateURI(
542 ->setSelected($key == 'tags'));
546 id(new PHUIListItemView())
548 ->setName(pht('History'))
549 ->setIcon('fa-history')
550 ->setHref($drequest->generateURI(
552 'action' => 'history',
554 ->setSelected($key == 'history'));