Path: blob/master/src/applications/diffusion/controller/DiffusionController.php
12242 views
<?php12abstract class DiffusionController extends PhabricatorController {34private $diffusionRequest;56protected function getDiffusionRequest() {7if (!$this->diffusionRequest) {8throw new PhutilInvalidStateException('loadDiffusionContext');9}10return $this->diffusionRequest;11}1213protected function hasDiffusionRequest() {14return (bool)$this->diffusionRequest;15}1617public function willBeginExecution() {18$request = $this->getRequest();1920// Check if this is a VCS request, e.g. from "git clone", "hg clone", or21// "svn checkout". If it is, we jump off into repository serving code to22// process the request.2324$serve_controller = new DiffusionServeController();25if ($serve_controller->isVCSRequest($request)) {26return $this->delegateToController($serve_controller);27}2829return parent::willBeginExecution();30}3132protected function loadDiffusionContextForEdit() {33return $this->loadContext(34array(35'edit' => true,36));37}3839protected function loadDiffusionContext() {40return $this->loadContext(array());41}4243private function loadContext(array $options) {44$request = $this->getRequest();45$viewer = $this->getViewer();46require_celerity_resource('diffusion-repository-css');4748$identifier = $this->getRepositoryIdentifierFromRequest($request);4950$params = $options + array(51'repository' => $identifier,52'user' => $viewer,53'blob' => $this->getDiffusionBlobFromRequest($request),54'commit' => $request->getURIData('commit'),55'path' => $request->getURIData('path'),56'line' => $request->getURIData('line'),57'branch' => $request->getURIData('branch'),58'lint' => $request->getStr('lint'),59);6061$drequest = DiffusionRequest::newFromDictionary($params);6263if (!$drequest) {64return new Aphront404Response();65}6667// If the client is making a request like "/diffusion/1/...", but the68// repository has a different canonical path like "/diffusion/XYZ/...",69// redirect them to the canonical path.7071// Skip this redirect if the request is an AJAX request, like the requests72// that Owners makes to complete and validate paths.7374if (!$request->isAjax()) {75$request_path = $request->getPath();76$repository = $drequest->getRepository();7778$canonical_path = $repository->getCanonicalPath($request_path);79if ($canonical_path !== null) {80if ($canonical_path != $request_path) {81return id(new AphrontRedirectResponse())->setURI($canonical_path);82}83}84}8586$this->diffusionRequest = $drequest;8788return null;89}9091protected function getDiffusionBlobFromRequest(AphrontRequest $request) {92return $request->getURIData('dblob');93}9495protected function getRepositoryIdentifierFromRequest(96AphrontRequest $request) {9798$short_name = $request->getURIData('repositoryShortName');99if ($short_name !== null && strlen($short_name)) {100// If the short name ends in ".git", ignore it.101$short_name = preg_replace('/\\.git\z/', '', $short_name);102return $short_name;103}104105$identifier = $request->getURIData('repositoryCallsign');106if ($identifier !== null && strlen($identifier)) {107return $identifier;108}109110$id = $request->getURIData('repositoryID');111if ($id !== null && strlen($id)) {112return (int)$id;113}114115return null;116}117118public function buildCrumbs(array $spec = array()) {119$crumbs = $this->buildApplicationCrumbs();120$crumb_list = $this->buildCrumbList($spec);121foreach ($crumb_list as $crumb) {122$crumbs->addCrumb($crumb);123}124return $crumbs;125}126127private function buildCrumbList(array $spec = array()) {128129$spec = $spec + array(130'commit' => null,131'tags' => null,132'branches' => null,133'view' => null,134);135136$crumb_list = array();137138// On the home page, we don't have a DiffusionRequest.139if ($this->hasDiffusionRequest()) {140$drequest = $this->getDiffusionRequest();141$repository = $drequest->getRepository();142} else {143$drequest = null;144$repository = null;145}146147if (!$repository) {148return $crumb_list;149}150151$repository_name = $repository->getName();152153if (!$spec['commit'] && !$spec['tags'] && !$spec['branches']) {154$branch_name = $drequest->getBranch();155if (strlen($branch_name)) {156$repository_name .= ' ('.$branch_name.')';157}158}159160$crumb = id(new PHUICrumbView())161->setName($repository_name);162if (!$spec['view'] && !$spec['commit'] &&163!$spec['tags'] && !$spec['branches']) {164$crumb_list[] = $crumb;165return $crumb_list;166}167$crumb->setHref(168$drequest->generateURI(169array(170'action' => 'branch',171'path' => '/',172)));173$crumb_list[] = $crumb;174175$stable_commit = $drequest->getStableCommit();176$commit_name = $repository->formatCommitName($stable_commit, $local = true);177$commit_uri = $repository->getCommitURI($stable_commit);178179if ($spec['tags']) {180$crumb = new PHUICrumbView();181if ($spec['commit']) {182$crumb->setName(pht('Tags for %s', $commit_name));183$crumb->setHref($commit_uri);184} else {185$crumb->setName(pht('Tags'));186}187$crumb_list[] = $crumb;188return $crumb_list;189}190191if ($spec['branches']) {192$crumb = id(new PHUICrumbView())193->setName(pht('Branches'));194$crumb_list[] = $crumb;195return $crumb_list;196}197198if ($spec['commit']) {199$crumb = id(new PHUICrumbView())200->setName($commit_name);201$crumb_list[] = $crumb;202return $crumb_list;203}204205$crumb = new PHUICrumbView();206$view = $spec['view'];207208switch ($view) {209case 'history':210$view_name = pht('History');211break;212case 'browse':213$view_name = pht('Browse');214break;215case 'lint':216$view_name = pht('Lint');217break;218case 'change':219$view_name = pht('Change');220break;221case 'compare':222$view_name = pht('Compare');223break;224}225226$crumb = id(new PHUICrumbView())227->setName($view_name);228229$crumb_list[] = $crumb;230return $crumb_list;231}232233protected function callConduitWithDiffusionRequest(234$method,235array $params = array()) {236237$user = $this->getRequest()->getUser();238$drequest = $this->getDiffusionRequest();239240return DiffusionQuery::callConduitWithDiffusionRequest(241$user,242$drequest,243$method,244$params);245}246247protected function callConduitMethod($method, array $params = array()) {248$user = $this->getViewer();249$drequest = $this->getDiffusionRequest();250251return DiffusionQuery::callConduitWithDiffusionRequest(252$user,253$drequest,254$method,255$params,256true);257}258259protected function getRepositoryControllerURI(260PhabricatorRepository $repository,261$path) {262return $repository->getPathURI($path);263}264265protected function renderPathLinks(DiffusionRequest $drequest, $action) {266$path = $drequest->getPath();267$path_parts = array();268if ($path !== null && strlen($path)) {269$path_parts = array_filter(explode('/', trim($path, '/')));270}271272$divider = phutil_tag(273'span',274array(275'class' => 'phui-header-divider',276),277'/');278279$links = array();280if ($path_parts) {281$links[] = phutil_tag(282'a',283array(284'href' => $drequest->generateURI(285array(286'action' => $action,287'path' => '',288)),289),290$drequest->getRepository()->getDisplayName());291$links[] = $divider;292$accum = '';293$last_key = last_key($path_parts);294foreach ($path_parts as $key => $part) {295$accum .= '/'.$part;296if ($key === $last_key) {297$links[] = $part;298} else {299$links[] = phutil_tag(300'a',301array(302'href' => $drequest->generateURI(303array(304'action' => $action,305'path' => $accum.'/',306)),307),308$part);309$links[] = $divider;310}311}312} else {313$links[] = $drequest->getRepository()->getDisplayName();314$links[] = $divider;315}316317return $links;318}319320protected function renderStatusMessage($title, $body) {321return id(new PHUIInfoView())322->setSeverity(PHUIInfoView::SEVERITY_NOTICE)323->setTitle($title)324->setFlush(true)325->appendChild($body);326}327328protected function renderCommitHashTag(DiffusionRequest $drequest) {329$stable_commit = $drequest->getStableCommit();330$commit = phutil_tag(331'a',332array(333'href' => $drequest->generateURI(334array(335'action' => 'commit',336'commit' => $stable_commit,337)),338),339$drequest->getRepository()->formatCommitName($stable_commit, true));340341$tag = id(new PHUITagView())342->setName($commit)343->setColor(PHUITagView::COLOR_INDIGO)344->setBorder(PHUITagView::BORDER_NONE)345->setType(PHUITagView::TYPE_SHADE);346347return $tag;348}349350protected function renderBranchTag(DiffusionRequest $drequest) {351$branch = $drequest->getBranch();352$branch = id(new PhutilUTF8StringTruncator())353->setMaximumGlyphs(24)354->truncateString($branch);355356$tag = id(new PHUITagView())357->setName($branch)358->setColor(PHUITagView::COLOR_INDIGO)359->setBorder(PHUITagView::BORDER_NONE)360->setType(PHUITagView::TYPE_OUTLINE)361->addClass('diffusion-header-branch-tag');362363return $tag;364}365366protected function renderSymbolicCommit(DiffusionRequest $drequest) {367$symbolic_tag = $drequest->getSymbolicCommit();368$symbolic_tag = id(new PhutilUTF8StringTruncator())369->setMaximumGlyphs(24)370->truncateString($symbolic_tag);371372$tag = id(new PHUITagView())373->setName($symbolic_tag)374->setIcon('fa-tag')375->setColor(PHUITagView::COLOR_INDIGO)376->setBorder(PHUITagView::BORDER_NONE)377->setType(PHUITagView::TYPE_SHADE);378379return $tag;380}381382protected function renderDirectoryReadme(DiffusionBrowseResultSet $browse) {383$readme_path = $browse->getReadmePath();384if ($readme_path === null) {385return null;386}387388$drequest = $this->getDiffusionRequest();389$viewer = $this->getViewer();390$repository = $drequest->getRepository();391$repository_phid = $repository->getPHID();392$stable_commit = $drequest->getStableCommit();393394$stable_commit_hash = PhabricatorHash::digestForIndex($stable_commit);395$readme_path_hash = PhabricatorHash::digestForIndex($readme_path);396397$cache = PhabricatorCaches::getMutableStructureCache();398$cache_key = "diffusion".399".repository({$repository_phid})".400".commit({$stable_commit_hash})".401".readme({$readme_path_hash})";402403$readme_cache = $cache->getKey($cache_key);404if (!$readme_cache) {405try {406$result = $this->callConduitWithDiffusionRequest(407'diffusion.filecontentquery',408array(409'path' => $readme_path,410'commit' => $drequest->getStableCommit(),411));412} catch (Exception $ex) {413return null;414}415416$file_phid = $result['filePHID'];417if (!$file_phid) {418return null;419}420421$file = id(new PhabricatorFileQuery())422->setViewer($viewer)423->withPHIDs(array($file_phid))424->executeOne();425if (!$file) {426return null;427}428429$corpus = $file->loadFileData();430431$readme_cache = array(432'corpus' => $corpus,433);434435$cache->setKey($cache_key, $readme_cache);436}437438$readme_corpus = $readme_cache['corpus'];439if (!strlen($readme_corpus)) {440return null;441}442443return id(new DiffusionReadmeView())444->setUser($this->getViewer())445->setPath($readme_path)446->setContent($readme_corpus);447}448449protected function renderSearchForm($path = '/') {450$drequest = $this->getDiffusionRequest();451$viewer = $this->getViewer();452switch ($drequest->getRepository()->getVersionControlSystem()) {453case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:454return null;455}456457$search_term = $this->getRequest()->getStr('grep');458require_celerity_resource('diffusion-icons-css');459require_celerity_resource('diffusion-css');460461$href = $drequest->generateURI(array(462'action' => 'browse',463'path' => $path,464));465466$bar = javelin_tag(467'input',468array(469'type' => 'text',470'id' => 'diffusion-search-input',471'name' => 'grep',472'class' => 'diffusion-search-input',473'sigil' => 'diffusion-search-input',474'placeholder' => pht('Pattern Search'),475'value' => $search_term,476));477478$form = phabricator_form(479$viewer,480array(481'method' => 'GET',482'action' => $href,483'sigil' => 'diffusion-search-form',484'class' => 'diffusion-search-form',485'id' => 'diffusion-search-form',486),487array(488$bar,489));490491$form_view = phutil_tag(492'div',493array(494'class' => 'diffusion-search-form-view',495),496$form);497498return $form_view;499}500501protected function buildTabsView($key) {502$drequest = $this->getDiffusionRequest();503$repository = $drequest->getRepository();504505$view = new PHUIListView();506507$view->addMenuItem(508id(new PHUIListItemView())509->setKey('code')510->setName(pht('Code'))511->setIcon('fa-code')512->setHref($drequest->generateURI(513array(514'action' => 'browse',515)))516->setSelected($key == 'code'));517518if (!$repository->isSVN()) {519$view->addMenuItem(520id(new PHUIListItemView())521->setKey('branch')522->setName(pht('Branches'))523->setIcon('fa-code-fork')524->setHref($drequest->generateURI(525array(526'action' => 'branches',527)))528->setSelected($key == 'branch'));529}530531if (!$repository->isSVN()) {532$view->addMenuItem(533id(new PHUIListItemView())534->setKey('tags')535->setName(pht('Tags'))536->setIcon('fa-tags')537->setHref($drequest->generateURI(538array(539'action' => 'tags',540)))541->setSelected($key == 'tags'));542}543544$view->addMenuItem(545id(new PHUIListItemView())546->setKey('history')547->setName(pht('History'))548->setIcon('fa-history')549->setHref($drequest->generateURI(550array(551'action' => 'history',552)))553->setSelected($key == 'history'));554555return $view;556557}558559}560561562