PageRenderTime 54ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/src/applications/diffusion/controller/DiffusionController.php

http://github.com/facebook/phabricator
PHP | 571 lines | 468 code | 93 blank | 10 comment | 43 complexity | 31e1b1fc24a623a848eb69be8a23f885 MD5 | raw file
Possible License(s): JSON, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause, LGPL-2.0, MIT, LGPL-2.1, LGPL-3.0
  1. <?php
  2. abstract class DiffusionController extends PhabricatorController {
  3. private $diffusionRequest;
  4. protected function getDiffusionRequest() {
  5. if (!$this->diffusionRequest) {
  6. throw new PhutilInvalidStateException('loadDiffusionContext');
  7. }
  8. return $this->diffusionRequest;
  9. }
  10. protected function hasDiffusionRequest() {
  11. return (bool)$this->diffusionRequest;
  12. }
  13. public function willBeginExecution() {
  14. $request = $this->getRequest();
  15. // Check if this is a VCS request, e.g. from "git clone", "hg clone", or
  16. // "svn checkout". If it is, we jump off into repository serving code to
  17. // process the request.
  18. $serve_controller = new DiffusionServeController();
  19. if ($serve_controller->isVCSRequest($request)) {
  20. return $this->delegateToController($serve_controller);
  21. }
  22. return parent::willBeginExecution();
  23. }
  24. protected function loadDiffusionContextForEdit() {
  25. return $this->loadContext(
  26. array(
  27. 'edit' => true,
  28. ));
  29. }
  30. protected function loadDiffusionContext() {
  31. return $this->loadContext(array());
  32. }
  33. private function loadContext(array $options) {
  34. $request = $this->getRequest();
  35. $viewer = $this->getViewer();
  36. require_celerity_resource('diffusion-repository-css');
  37. $identifier = $this->getRepositoryIdentifierFromRequest($request);
  38. $params = $options + array(
  39. 'repository' => $identifier,
  40. 'user' => $viewer,
  41. 'blob' => $this->getDiffusionBlobFromRequest($request),
  42. 'commit' => $request->getURIData('commit'),
  43. 'path' => $request->getURIData('path'),
  44. 'line' => $request->getURIData('line'),
  45. 'branch' => $request->getURIData('branch'),
  46. 'lint' => $request->getStr('lint'),
  47. );
  48. $drequest = DiffusionRequest::newFromDictionary($params);
  49. if (!$drequest) {
  50. return new Aphront404Response();
  51. }
  52. // If the client is making a request like "/diffusion/1/...", but the
  53. // repository has a different canonical path like "/diffusion/XYZ/...",
  54. // redirect them to the canonical path.
  55. // Skip this redirect if the request is an AJAX request, like the requests
  56. // that Owners makes to complete and validate paths.
  57. if (!$request->isAjax()) {
  58. $request_path = $request->getPath();
  59. $repository = $drequest->getRepository();
  60. $canonical_path = $repository->getCanonicalPath($request_path);
  61. if ($canonical_path !== null) {
  62. if ($canonical_path != $request_path) {
  63. return id(new AphrontRedirectResponse())->setURI($canonical_path);
  64. }
  65. }
  66. }
  67. $this->diffusionRequest = $drequest;
  68. return null;
  69. }
  70. protected function getDiffusionBlobFromRequest(AphrontRequest $request) {
  71. return $request->getURIData('dblob');
  72. }
  73. protected function getRepositoryIdentifierFromRequest(
  74. AphrontRequest $request) {
  75. $short_name = $request->getURIData('repositoryShortName');
  76. if (strlen($short_name)) {
  77. // If the short name ends in ".git", ignore it.
  78. $short_name = preg_replace('/\\.git\z/', '', $short_name);
  79. return $short_name;
  80. }
  81. $identifier = $request->getURIData('repositoryCallsign');
  82. if (strlen($identifier)) {
  83. return $identifier;
  84. }
  85. $id = $request->getURIData('repositoryID');
  86. if (strlen($id)) {
  87. return (int)$id;
  88. }
  89. return null;
  90. }
  91. public function buildCrumbs(array $spec = array()) {
  92. $crumbs = $this->buildApplicationCrumbs();
  93. $crumb_list = $this->buildCrumbList($spec);
  94. foreach ($crumb_list as $crumb) {
  95. $crumbs->addCrumb($crumb);
  96. }
  97. return $crumbs;
  98. }
  99. private function buildCrumbList(array $spec = array()) {
  100. $spec = $spec + array(
  101. 'commit' => null,
  102. 'tags' => null,
  103. 'branches' => null,
  104. 'view' => null,
  105. );
  106. $crumb_list = array();
  107. // On the home page, we don't have a DiffusionRequest.
  108. if ($this->hasDiffusionRequest()) {
  109. $drequest = $this->getDiffusionRequest();
  110. $repository = $drequest->getRepository();
  111. } else {
  112. $drequest = null;
  113. $repository = null;
  114. }
  115. if (!$repository) {
  116. return $crumb_list;
  117. }
  118. $repository_name = $repository->getName();
  119. if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) {
  120. $branch_name = $drequest->getBranch();
  121. if (strlen($branch_name)) {
  122. $repository_name .= ' ('.$branch_name.')';
  123. }
  124. }
  125. $crumb = id(new PHUICrumbView())
  126. ->setName($repository_name);
  127. if (!$spec['view'] && !$spec['commit'] &&
  128. !$spec['tags'] && !$spec['branches']) {
  129. $crumb_list[] = $crumb;
  130. return $crumb_list;
  131. }
  132. $crumb->setHref(
  133. $drequest->generateURI(
  134. array(
  135. 'action' => 'branch',
  136. 'path' => '/',
  137. )));
  138. $crumb_list[] = $crumb;
  139. $stable_commit = $drequest->getStableCommit();
  140. $commit_name = $repository->formatCommitName($stable_commit, $local = true);
  141. $commit_uri = $repository->getCommitURI($stable_commit);
  142. if ($spec['tags']) {
  143. $crumb = new PHUICrumbView();
  144. if ($spec['commit']) {
  145. $crumb->setName(pht('Tags for %s', $commit_name));
  146. $crumb->setHref($commit_uri);
  147. } else {
  148. $crumb->setName(pht('Tags'));
  149. }
  150. $crumb_list[] = $crumb;
  151. return $crumb_list;
  152. }
  153. if ($spec['branches']) {
  154. $crumb = id(new PHUICrumbView())
  155. ->setName(pht('Branches'));
  156. $crumb_list[] = $crumb;
  157. return $crumb_list;
  158. }
  159. if ($spec['commit']) {
  160. $crumb = id(new PHUICrumbView())
  161. ->setName($commit_name);
  162. $crumb_list[] = $crumb;
  163. return $crumb_list;
  164. }
  165. $crumb = new PHUICrumbView();
  166. $view = $spec['view'];
  167. switch ($view) {
  168. case 'history':
  169. $view_name = pht('History');
  170. break;
  171. case 'graph':
  172. $view_name = pht('Graph');
  173. break;
  174. case 'browse':
  175. $view_name = pht('Browse');
  176. break;
  177. case 'lint':
  178. $view_name = pht('Lint');
  179. break;
  180. case 'change':
  181. $view_name = pht('Change');
  182. break;
  183. case 'compare':
  184. $view_name = pht('Compare');
  185. break;
  186. }
  187. $crumb = id(new PHUICrumbView())
  188. ->setName($view_name);
  189. $crumb_list[] = $crumb;
  190. return $crumb_list;
  191. }
  192. protected function callConduitWithDiffusionRequest(
  193. $method,
  194. array $params = array()) {
  195. $user = $this->getRequest()->getUser();
  196. $drequest = $this->getDiffusionRequest();
  197. return DiffusionQuery::callConduitWithDiffusionRequest(
  198. $user,
  199. $drequest,
  200. $method,
  201. $params);
  202. }
  203. protected function callConduitMethod($method, array $params = array()) {
  204. $user = $this->getViewer();
  205. $drequest = $this->getDiffusionRequest();
  206. return DiffusionQuery::callConduitWithDiffusionRequest(
  207. $user,
  208. $drequest,
  209. $method,
  210. $params,
  211. true);
  212. }
  213. protected function getRepositoryControllerURI(
  214. PhabricatorRepository $repository,
  215. $path) {
  216. return $repository->getPathURI($path);
  217. }
  218. protected function renderPathLinks(DiffusionRequest $drequest, $action) {
  219. $path = $drequest->getPath();
  220. $path_parts = array_filter(explode('/', trim($path, '/')));
  221. $divider = phutil_tag(
  222. 'span',
  223. array(
  224. 'class' => 'phui-header-divider',
  225. ),
  226. '/');
  227. $links = array();
  228. if ($path_parts) {
  229. $links[] = phutil_tag(
  230. 'a',
  231. array(
  232. 'href' => $drequest->generateURI(
  233. array(
  234. 'action' => $action,
  235. 'path' => '',
  236. )),
  237. ),
  238. $drequest->getRepository()->getDisplayName());
  239. $links[] = $divider;
  240. $accum = '';
  241. $last_key = last_key($path_parts);
  242. foreach ($path_parts as $key => $part) {
  243. $accum .= '/'.$part;
  244. if ($key === $last_key) {
  245. $links[] = $part;
  246. } else {
  247. $links[] = phutil_tag(
  248. 'a',
  249. array(
  250. 'href' => $drequest->generateURI(
  251. array(
  252. 'action' => $action,
  253. 'path' => $accum.'/',
  254. )),
  255. ),
  256. $part);
  257. $links[] = $divider;
  258. }
  259. }
  260. } else {
  261. $links[] = $drequest->getRepository()->getDisplayName();
  262. $links[] = $divider;
  263. }
  264. return $links;
  265. }
  266. protected function renderStatusMessage($title, $body) {
  267. return id(new PHUIInfoView())
  268. ->setSeverity(PHUIInfoView::SEVERITY_NOTICE)
  269. ->setTitle($title)
  270. ->setFlush(true)
  271. ->appendChild($body);
  272. }
  273. protected function renderCommitHashTag(DiffusionRequest $drequest) {
  274. $stable_commit = $drequest->getStableCommit();
  275. $commit = phutil_tag(
  276. 'a',
  277. array(
  278. 'href' => $drequest->generateURI(
  279. array(
  280. 'action' => 'commit',
  281. 'commit' => $stable_commit,
  282. )),
  283. ),
  284. $drequest->getRepository()->formatCommitName($stable_commit, true));
  285. $tag = id(new PHUITagView())
  286. ->setName($commit)
  287. ->setColor(PHUITagView::COLOR_INDIGO)
  288. ->setBorder(PHUITagView::BORDER_NONE)
  289. ->setType(PHUITagView::TYPE_SHADE);
  290. return $tag;
  291. }
  292. protected function renderBranchTag(DiffusionRequest $drequest) {
  293. $branch = $drequest->getBranch();
  294. $branch = id(new PhutilUTF8StringTruncator())
  295. ->setMaximumGlyphs(24)
  296. ->truncateString($branch);
  297. $tag = id(new PHUITagView())
  298. ->setName($branch)
  299. ->setColor(PHUITagView::COLOR_INDIGO)
  300. ->setBorder(PHUITagView::BORDER_NONE)
  301. ->setType(PHUITagView::TYPE_OUTLINE)
  302. ->addClass('diffusion-header-branch-tag');
  303. return $tag;
  304. }
  305. protected function renderSymbolicCommit(DiffusionRequest $drequest) {
  306. $symbolic_tag = $drequest->getSymbolicCommit();
  307. $symbolic_tag = id(new PhutilUTF8StringTruncator())
  308. ->setMaximumGlyphs(24)
  309. ->truncateString($symbolic_tag);
  310. $tag = id(new PHUITagView())
  311. ->setName($symbolic_tag)
  312. ->setIcon('fa-tag')
  313. ->setColor(PHUITagView::COLOR_INDIGO)
  314. ->setBorder(PHUITagView::BORDER_NONE)
  315. ->setType(PHUITagView::TYPE_SHADE);
  316. return $tag;
  317. }
  318. protected function renderDirectoryReadme(DiffusionBrowseResultSet $browse) {
  319. $readme_path = $browse->getReadmePath();
  320. if ($readme_path === null) {
  321. return null;
  322. }
  323. $drequest = $this->getDiffusionRequest();
  324. $viewer = $this->getViewer();
  325. $repository = $drequest->getRepository();
  326. $repository_phid = $repository->getPHID();
  327. $stable_commit = $drequest->getStableCommit();
  328. $stable_commit_hash = PhabricatorHash::digestForIndex($stable_commit);
  329. $readme_path_hash = PhabricatorHash::digestForIndex($readme_path);
  330. $cache = PhabricatorCaches::getMutableStructureCache();
  331. $cache_key = "diffusion".
  332. ".repository({$repository_phid})".
  333. ".commit({$stable_commit_hash})".
  334. ".readme({$readme_path_hash})";
  335. $readme_cache = $cache->getKey($cache_key);
  336. if (!$readme_cache) {
  337. try {
  338. $result = $this->callConduitWithDiffusionRequest(
  339. 'diffusion.filecontentquery',
  340. array(
  341. 'path' => $readme_path,
  342. 'commit' => $drequest->getStableCommit(),
  343. ));
  344. } catch (Exception $ex) {
  345. return null;
  346. }
  347. $file_phid = $result['filePHID'];
  348. if (!$file_phid) {
  349. return null;
  350. }
  351. $file = id(new PhabricatorFileQuery())
  352. ->setViewer($viewer)
  353. ->withPHIDs(array($file_phid))
  354. ->executeOne();
  355. if (!$file) {
  356. return null;
  357. }
  358. $corpus = $file->loadFileData();
  359. $readme_cache = array(
  360. 'corpus' => $corpus,
  361. );
  362. $cache->setKey($cache_key, $readme_cache);
  363. }
  364. $readme_corpus = $readme_cache['corpus'];
  365. if (!strlen($readme_corpus)) {
  366. return null;
  367. }
  368. return id(new DiffusionReadmeView())
  369. ->setUser($this->getViewer())
  370. ->setPath($readme_path)
  371. ->setContent($readme_corpus);
  372. }
  373. protected function renderSearchForm($path = '/') {
  374. $drequest = $this->getDiffusionRequest();
  375. $viewer = $this->getViewer();
  376. switch ($drequest->getRepository()->getVersionControlSystem()) {
  377. case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
  378. return null;
  379. }
  380. $search_term = $this->getRequest()->getStr('grep');
  381. require_celerity_resource('diffusion-icons-css');
  382. require_celerity_resource('diffusion-css');
  383. $href = $drequest->generateURI(array(
  384. 'action' => 'browse',
  385. 'path' => $path,
  386. ));
  387. $bar = javelin_tag(
  388. 'input',
  389. array(
  390. 'type' => 'text',
  391. 'id' => 'diffusion-search-input',
  392. 'name' => 'grep',
  393. 'class' => 'diffusion-search-input',
  394. 'sigil' => 'diffusion-search-input',
  395. 'placeholder' => pht('Pattern Search'),
  396. 'value' => $search_term,
  397. ));
  398. $form = phabricator_form(
  399. $viewer,
  400. array(
  401. 'method' => 'GET',
  402. 'action' => $href,
  403. 'sigil' => 'diffusion-search-form',
  404. 'class' => 'diffusion-search-form',
  405. 'id' => 'diffusion-search-form',
  406. ),
  407. array(
  408. $bar,
  409. ));
  410. $form_view = phutil_tag(
  411. 'div',
  412. array(
  413. 'class' => 'diffusion-search-form-view',
  414. ),
  415. $form);
  416. return $form_view;
  417. }
  418. protected function buildTabsView($key) {
  419. $drequest = $this->getDiffusionRequest();
  420. $repository = $drequest->getRepository();
  421. $view = new PHUIListView();
  422. $view->addMenuItem(
  423. id(new PHUIListItemView())
  424. ->setKey('code')
  425. ->setName(pht('Code'))
  426. ->setIcon('fa-code')
  427. ->setHref($drequest->generateURI(
  428. array(
  429. 'action' => 'browse',
  430. )))
  431. ->setSelected($key == 'code'));
  432. if (!$repository->isSVN()) {
  433. $view->addMenuItem(
  434. id(new PHUIListItemView())
  435. ->setKey('branch')
  436. ->setName(pht('Branches'))
  437. ->setIcon('fa-code-fork')
  438. ->setHref($drequest->generateURI(
  439. array(
  440. 'action' => 'branches',
  441. )))
  442. ->setSelected($key == 'branch'));
  443. }
  444. if (!$repository->isSVN()) {
  445. $view->addMenuItem(
  446. id(new PHUIListItemView())
  447. ->setKey('tags')
  448. ->setName(pht('Tags'))
  449. ->setIcon('fa-tags')
  450. ->setHref($drequest->generateURI(
  451. array(
  452. 'action' => 'tags',
  453. )))
  454. ->setSelected($key == 'tags'));
  455. }
  456. $view->addMenuItem(
  457. id(new PHUIListItemView())
  458. ->setKey('history')
  459. ->setName(pht('History'))
  460. ->setIcon('fa-history')
  461. ->setHref($drequest->generateURI(
  462. array(
  463. 'action' => 'history',
  464. )))
  465. ->setSelected($key == 'history'));
  466. $view->addMenuItem(
  467. id(new PHUIListItemView())
  468. ->setKey('graph')
  469. ->setName(pht('Graph'))
  470. ->setIcon('fa-code-fork')
  471. ->setHref($drequest->generateURI(
  472. array(
  473. 'action' => 'graph',
  474. )))
  475. ->setSelected($key == 'graph'));
  476. return $view;
  477. }
  478. }