Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2894174
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Advanced/Developer...
View Handle
View Hovercard
Size
15 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
rP Phorge
Attached
Detach File
Event Timeline
Log In to Comment