Page MenuHomePhorge

No OneTemporary

diff --git a/src/applications/diffusion/controller/DiffusionBrowseController.php b/src/applications/diffusion/controller/DiffusionBrowseController.php
index d720ad8872..be2df62dad 100644
--- a/src/applications/diffusion/controller/DiffusionBrowseController.php
+++ b/src/applications/diffusion/controller/DiffusionBrowseController.php
@@ -1,123 +1,296 @@
<?php
final class DiffusionBrowseController extends DiffusionController {
public function processRequest() {
$drequest = $this->diffusionRequest;
+ $is_file = false;
if ($this->getRequest()->getStr('before')) {
- $results = array();
$is_file = true;
- } else {
+ } else if ($this->getRequest()->getStr('grep') == '') {
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
$browse_query->setViewer($this->getRequest()->getUser());
$results = $browse_query->loadPaths();
$reason = $browse_query->getReasonForEmptyResultSet();
$is_file = ($reason == DiffusionBrowseQuery::REASON_IS_FILE);
}
+ if ($is_file) {
+ $controller = new DiffusionBrowseFileController($this->getRequest());
+ $controller->setDiffusionRequest($drequest);
+ $controller->setCurrentApplication($this->getCurrentApplication());
+ return $this->delegateToController($controller);
+ }
+
$content = array();
if ($drequest->getTagContent()) {
$title = 'Tag: '.$drequest->getSymbolicCommit();
$tag_view = new AphrontPanelView();
$tag_view->setHeader($title);
$tag_view->appendChild(
$this->markupText($drequest->getTagContent()));
$content[] = $tag_view;
}
- if (!$results) {
+ $content[] = $this->renderSearchForm();
- if ($is_file) {
- $controller = new DiffusionBrowseFileController($this->getRequest());
- $controller->setDiffusionRequest($drequest);
- $controller->setCurrentApplication($this->getCurrentApplication());
- return $this->delegateToController($controller);
- }
-
- $empty_result = new DiffusionEmptyResultView();
- $empty_result->setDiffusionRequest($drequest);
- $empty_result->setBrowseQuery($browse_query);
- $empty_result->setView($this->getRequest()->getStr('view'));
- $content[] = $empty_result;
+ if ($this->getRequest()->getStr('grep') != '') {
+ $content[] = $this->renderSearchResults();
} else {
+ if (!$results) {
+ $empty_result = new DiffusionEmptyResultView();
+ $empty_result->setDiffusionRequest($drequest);
+ $empty_result->setBrowseQuery($browse_query);
+ $empty_result->setView($this->getRequest()->getStr('view'));
+ $content[] = $empty_result;
+
+ } else {
- $phids = array();
- foreach ($results as $result) {
- $data = $result->getLastCommitData();
- if ($data) {
- if ($data->getCommitDetail('authorPHID')) {
- $phids[$data->getCommitDetail('authorPHID')] = true;
+ $phids = array();
+ foreach ($results as $result) {
+ $data = $result->getLastCommitData();
+ if ($data) {
+ if ($data->getCommitDetail('authorPHID')) {
+ $phids[$data->getCommitDetail('authorPHID')] = true;
+ }
}
}
- }
- $phids = array_keys($phids);
- $handles = $this->loadViewerHandles($phids);
+ $phids = array_keys($phids);
+ $handles = $this->loadViewerHandles($phids);
- $browse_table = new DiffusionBrowseTableView();
- $browse_table->setDiffusionRequest($drequest);
- $browse_table->setHandles($handles);
- $browse_table->setPaths($results);
- $browse_table->setUser($this->getRequest()->getUser());
+ $browse_table = new DiffusionBrowseTableView();
+ $browse_table->setDiffusionRequest($drequest);
+ $browse_table->setHandles($handles);
+ $browse_table->setPaths($results);
+ $browse_table->setUser($this->getRequest()->getUser());
- $browse_panel = new AphrontPanelView();
- $browse_panel->appendChild($browse_table);
- $browse_panel->setNoBackground();
+ $browse_panel = new AphrontPanelView();
+ $browse_panel->appendChild($browse_table);
+ $browse_panel->setNoBackground();
- $content[] = $browse_panel;
- }
+ $content[] = $browse_panel;
+ }
- $content[] = $this->buildOpenRevisions();
+ $content[] = $this->buildOpenRevisions();
- $readme_content = $browse_query->renderReadme($results);
- if ($readme_content) {
- $readme_panel = new AphrontPanelView();
- $readme_panel->setHeader('README');
- $readme_panel->appendChild($readme_content);
+ $readme_content = $browse_query->renderReadme($results);
+ if ($readme_content) {
+ $readme_panel = new AphrontPanelView();
+ $readme_panel->setHeader('README');
+ $readme_panel->appendChild($readme_content);
- $content[] = $readme_panel;
+ $content[] = $readme_panel;
+ }
}
-
$nav = $this->buildSideNav('browse', false);
$nav->appendChild($content);
$crumbs = $this->buildCrumbs(
array(
'branch' => true,
'path' => true,
'view' => 'browse',
));
$nav->setCrumbs($crumbs);
return $this->buildApplicationPage(
$nav,
array(
'title' => array(
nonempty(basename($drequest->getPath()), '/'),
$drequest->getRepository()->getCallsign().' Repository',
),
));
}
+
+ private function renderSearchForm() {
+ $drequest = $this->getDiffusionRequest();
+ $form = id(new AphrontFormView())
+ ->setUser($this->getRequest()->getUser())
+ ->setMethod('GET');
+
+ switch ($drequest->getRepository()->getVersionControlSystem()) {
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
+ $form->appendChild(pht('Search is not available in Subversion.'));
+ break;
+
+ default:
+ $form
+ ->appendChild(
+ id(new AphrontFormTextControl())
+ ->setLabel(pht('Search Here'))
+ ->setName('grep')
+ ->setValue($this->getRequest()->getStr('grep'))
+ ->setCaption(pht('Regular expression')))
+ ->appendChild(
+ id(new AphrontFormSubmitControl())
+ ->setValue(pht('Grep')));
+ break;
+ }
+
+ return $form;
+ }
+
+ private function renderSearchResults() {
+ $drequest = $this->getDiffusionRequest();
+ $repository = $drequest->getRepository();
+ $results = array();
+ $no_data = pht('No results found.');
+
+ $limit = 100;
+ $page = $this->getRequest()->getInt('page', 0);
+ $pager = new AphrontPagerView();
+ $pager->setPageSize($limit);
+ $pager->setOffset($page);
+ $pager->setURI($this->getRequest()->getRequestURI(), 'page');
+
+ try {
+
+ switch ($repository->getVersionControlSystem()) {
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
+ $future = $repository->getLocalCommandFuture(
+ // NOTE: --perl-regexp is available only with libpcre compiled in.
+ 'grep --extended-regexp --null -n --no-color -e %s %s -- %s',
+ $this->getRequest()->getStr('grep'),
+ $drequest->getStableCommitName(),
+ $drequest->getPath());
+
+ $binary_pattern = '/Binary file [^:]*:(.+) matches/';
+ $lines = new LinesOfALargeExecFuture($future);
+ foreach ($lines as $line) {
+ $result = null;
+ if (preg_match('/[^:]*:(.+)\0(.+)\0(.*)/', $line, $result)) {
+ $results[] = array_slice($result, 1);
+ } else if (preg_match($binary_pattern, $line, $result)) {
+ list(, $path) = $result;
+ $results[] = array($path, null, pht('Binary file'));
+ } else {
+ $results[] = array(null, null, $line);
+ }
+ if (count($results) > $page + $limit) {
+ break;
+ }
+ }
+ unset($lines);
+
+ break;
+
+ case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
+ $future = $repository->getLocalCommandFuture(
+ 'grep --rev %s --print0 --line-number %s %s',
+ hgsprintf('ancestors(%s)', $drequest->getStableCommitName()),
+ $this->getRequest()->getStr('grep'),
+ $drequest->getPath());
+
+ $lines = id(new LinesOfALargeExecFuture($future))->setDelimiter("\0");
+ $parts = array();
+ foreach ($lines as $line) {
+ $parts[] = $line;
+ if (count($parts) == 4) {
+ list($path, $offset, $line, $string) = $parts;
+ $results[] = array($path, $line, $string);
+ if (count($results) > $page + $limit) {
+ break;
+ }
+ $parts = array();
+ }
+ }
+ unset($lines);
+
+ break;
+ }
+
+ } catch (CommandException $ex) {
+ return id(new AphrontErrorView())
+ ->setTitle(pht('Search Error'))
+ ->appendChild($ex->getStderr());
+ }
+
+ $results = array_slice($results, $page);
+ $results = $pager->sliceResults($results);
+
+ require_celerity_resource('syntax-highlighting-css');
+
+ // NOTE: This can be wrong because we may find the string inside the
+ // comment. But it's correct in most cases and highlighting the whole file
+ // would be too expensive.
+ $futures = array();
+ $engine = PhabricatorSyntaxHighlighter::newEngine();
+ foreach ($results as $result) {
+ list($path, $line, $string) = $result;
+ $futures["{$path}:{$line}"] = $engine->getHighlightFuture(
+ $engine->getLanguageFromFilename($path),
+ ltrim($string));
+ }
+
+ try {
+ Futures($futures)->limit(8)->resolveAll();
+ } catch (PhutilSyntaxHighlighterException $ex) {
+ }
+
+ $rows = array();
+ foreach ($results as $result) {
+ list($path, $line, $string) = $result;
+
+ $href = $drequest->generateURI(array(
+ 'action' => 'browse',
+ 'path' => $path,
+ 'line' => $line,
+ ));
+
+ try {
+ $string = $futures["{$path}:{$line}"]->resolve();
+ } catch (PhutilSyntaxHighlighterException $ex) {
+ }
+
+ $string = phutil_tag(
+ 'pre',
+ array('class' => 'PhabricatorMonospaced'),
+ $string);
+
+ $path = Filesystem::readablePath($path, $drequest->getPath());
+
+ $rows[] = array(
+ phutil_tag('a', array('href' => $href), $path),
+ $line,
+ $string,
+ );
+ }
+
+ $table = id(new AphrontTableView($rows))
+ ->setClassName('remarkup-code')
+ ->setHeaders(array(pht('Path'), pht('Line'), pht('String')))
+ ->setColumnClasses(array('', 'n', 'wide'))
+ ->setNoDataString($no_data);
+
+ return id(new AphrontPanelView())
+ ->setHeader(pht('Search Results'))
+ ->appendChild($table)
+ ->appendChild($pager);
+ }
+
+
private function markupText($text) {
$engine = PhabricatorMarkupEngine::newDiffusionMarkupEngine();
$engine->setConfig('viewer', $this->getRequest()->getUser());
$text = $engine->markupText($text);
$text = phutil_tag(
'div',
array(
'class' => 'phabricator-remarkup',
),
$text);
return $text;
}
}
diff --git a/src/applications/diffusion/query/browse/DiffusionBrowseQuery.php b/src/applications/diffusion/query/browse/DiffusionBrowseQuery.php
index d2151dd183..a0711f9aa7 100644
--- a/src/applications/diffusion/query/browse/DiffusionBrowseQuery.php
+++ b/src/applications/diffusion/query/browse/DiffusionBrowseQuery.php
@@ -1,157 +1,158 @@
<?php
abstract class DiffusionBrowseQuery {
private $request;
protected $reason;
protected $existedAtCommit;
protected $deletedAtCommit;
protected $validityOnly;
private $viewer;
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
return $this;
}
public function getViewer() {
return $this->viewer;
}
const REASON_IS_FILE = 'is-file';
const REASON_IS_DELETED = 'is-deleted';
const REASON_IS_NONEXISTENT = 'nonexistent';
const REASON_BAD_COMMIT = 'bad-commit';
const REASON_IS_EMPTY = 'empty';
const REASON_IS_UNTRACKED_PARENT = 'untracked-parent';
final private function __construct() {
// <private>
}
final public static function newFromDiffusionRequest(
DiffusionRequest $request) {
$repository = $request->getRepository();
switch ($repository->getVersionControlSystem()) {
case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT:
// TODO: Verify local-path?
$query = new DiffusionGitBrowseQuery();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL:
$query = new DiffusionMercurialBrowseQuery();
break;
case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN:
$query = new DiffusionSvnBrowseQuery();
break;
default:
throw new Exception("Unsupported VCS!");
}
$query->request = $request;
return $query;
}
final protected function getRequest() {
return $this->request;
}
final public function getReasonForEmptyResultSet() {
return $this->reason;
}
final public function getExistedAtCommit() {
return $this->existedAtCommit;
}
final public function getDeletedAtCommit() {
return $this->deletedAtCommit;
}
final public function loadPaths() {
+ $this->reason = null;
return $this->executeQuery();
}
final public function shouldOnlyTestValidity() {
return $this->validityOnly;
}
final public function needValidityOnly($need_validity_only) {
$this->validityOnly = $need_validity_only;
return $this;
}
final public function renderReadme(array $results) {
$drequest = $this->getRequest();
$readme = null;
foreach ($results as $result) {
$file_type = $result->getFileType();
if (($file_type != ArcanistDiffChangeType::FILE_NORMAL) &&
($file_type != ArcanistDiffChangeType::FILE_TEXT)) {
// Skip directories, etc.
continue;
}
$path = $result->getPath();
if (preg_match('/^readme(|\.txt|\.remarkup|\.rainbow)$/i', $path)) {
$readme = $result;
break;
}
}
if (!$readme) {
return null;
}
$readme_request = DiffusionRequest::newFromDictionary(
array(
'repository' => $drequest->getRepository(),
'commit' => $drequest->getStableCommitName(),
'path' => $readme->getFullPath(),
));
$content_query = DiffusionFileContentQuery::newFromDiffusionRequest(
$readme_request);
$content_query->setViewer($this->getViewer());
$content_query->loadFileContent();
$readme_content = $content_query->getRawData();
if (preg_match('/\\.txt$/', $readme->getPath())) {
$readme_content = phutil_escape_html_newlines($readme_content);
$class = null;
} else if (preg_match('/\\.rainbow$/', $readme->getPath())) {
$highlighter = new PhutilRainbowSyntaxHighlighter();
$readme_content = $highlighter
->getHighlightFuture($readme_content)
->resolve();
$readme_content = phutil_escape_html_newlines($readme_content);
require_celerity_resource('syntax-highlighting-css');
$class = 'remarkup-code';
} else {
// Markup extensionless files as remarkup so we get links and such.
$engine = PhabricatorMarkupEngine::newDiffusionMarkupEngine();
$engine->setConfig('viewer', $this->getViewer());
$readme_content = $engine->markupText($readme_content);
$class = 'phabricator-remarkup';
}
$readme_content = phutil_tag(
'div',
array(
'class' => $class,
),
$readme_content);
return $readme_content;
}
abstract protected function executeQuery();
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Jan 19, 19:30 (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1127994
Default Alt Text
(15 KB)

Event Timeline