Implementing search feature for trees and commit log

This commit is contained in:
Klaus Silveira
2012-09-15 14:13:40 -03:00
parent e17ffee12d
commit 50f6a1004b
9 changed files with 165 additions and 6 deletions

View File

@@ -6,6 +6,7 @@ use Silex\Application;
use Silex\ControllerProviderInterface;
use Silex\ControllerCollection;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
class CommitController implements ControllerProviderInterface
{
@@ -43,6 +44,27 @@ class CommitController implements ControllerProviderInterface
->value('file', '')
->bind('commits');
$route->post('{repo}/commits/search', function(Request $request, $repo) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commits = $repository->searchCommitLog($request->get('query'));
foreach ($commits as $commit) {
$date = $commit->getDate();
$date = $date->format('m/d/Y');
$categorized[$date][] = $commit;
}
return $app['twig']->render('searchcommits.twig', array(
'repo' => $repo,
'branch' => 'master',
'file' => '',
'commits' => $categorized,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
));
})->assert('repo', '[\w-._]+')
->bind('searchcommits');
$route->get('{repo}/commit/{commit}/', function($repo, $commit) use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
$commit = $repository->getCommit($commit);

View File

@@ -7,6 +7,7 @@ use Silex\ControllerProviderInterface;
use Silex\ControllerCollection;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\HttpFoundation\Request;
class TreeController implements ControllerProviderInterface
{
@@ -45,6 +46,29 @@ class TreeController implements ControllerProviderInterface
->assert('tree', '.+')
->bind('tree');
$route->post('{repo}/tree/{branch}/search', function(Request $request, $repo, $branch = '', $tree = '') use ($app) {
$repository = $app['git']->getRepository($app['git.repos'] . $repo);
if (!$branch) {
$branch = $repository->getHead();
}
$breadcrumbs = $app['util.view']->getBreadcrumbs($tree);
$results = $repository->searchTree($request->get('query'), $branch);
return $app['twig']->render('search.twig', array(
'results' => $results,
'repo' => $repo,
'branch' => $branch,
'path' => $tree,
'breadcrumbs' => $breadcrumbs,
'branches' => $repository->getBranches(),
'tags' => $repository->getTags(),
));
})->assert('repo', '[\w-._]+')
->assert('branch', '[\w-._]+')
->bind('search');
$route->get('{repo}/{branch}/', function($repo, $branch) use ($app, $treeController) {
return $treeController($repo, $branch);
})->assert('repo', '[\w-._]+')

View File

@@ -35,6 +35,47 @@ class Repository extends BaseRepository
return $commits;
}
public function searchCommitLog($query)
{
$command = "log --grep='$query' --pretty=format:'<item><hash>%H</hash><short_hash>%h</short_hash><tree>%T</tree><parent>%P</parent><author>%an</author><author_email>%ae</author_email><date>%at</date><commiter>%cn</commiter><commiter_email>%ce</commiter_email><commiter_date>%ct</commiter_date><message><![CDATA[%s]]></message></item>'";
$logs = $this->getPrettyFormat($command);
foreach ($logs as $log) {
$commit = new Commit;
$commit->importData($log);
$commits[] = $commit;
}
return $commits;
}
public function searchTree($query, $branch)
{
try {
$results = $this->getClient()->run($this, "grep --line-number '$query' $branch");
} catch (\RuntimeException $e) {
return false;
}
$results = explode("\n", $results);
foreach ($results as $result) {
if ($result == '') {
continue;
}
preg_match_all('/([\w-._]+):(.+):([0-9]+):(.+)/', $result, $matches, PREG_SET_ORDER);
$data['branch'] = $matches[0][1];
$data['file'] = $matches[0][2];
$data['line'] = $matches[0][3];
$data['match'] = $matches[0][4];
$searchResults[] = $data;
}
return $searchResults;
}
public function getAuthorStatistics()
{
$logs = $this->getClient()->run($this, 'log --pretty=format:"%an||%ae" ' . $this->getHead());

View File

@@ -20,6 +20,7 @@
</table>
{% endfor %}
{% if page != 'searchcommits' %}
<ul class="pager">
{% if pager.current != 0 %}
<li class="previous">
@@ -32,3 +33,4 @@
</li>
{% endif %}
</ul>
{% endif %}

View File

@@ -6,9 +6,20 @@
<div class="container">
<div class="row">
<div class="span12">
{% if page == 'commits' %}
<form class="form-search pull-right" action="{{ app.request.basepath }}/{{repo}}/commits/search" method="POST">
<input type="text" name="query" class="input-medium search-query" placeholder="Search commits...">
</form>
{% else %}
<form class="form-search pull-right" action="{{ app.request.basepath }}/{{repo}}/tree/{{branch}}/search" method="POST">
<input type="text" name="query" class="input-medium search-query" placeholder="Search tree...">
</form>
{% endif %}
{% if branches is defined %}
{% include 'branch_menu.twig' %}
{% endif %}
{% include 'menu.twig' %}
</div>
</div>

42
views/search.twig Normal file
View File

@@ -0,0 +1,42 @@
{% extends 'layout_page.twig' %}
{% set page = 'files' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% embed 'breadcrumb.twig' with {breadcrumbs: breadcrumbs} %}
{% block extra %}
<div class="pull-right">
<div class="btn-group download-buttons">
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'zip'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a ZIP archive">ZIP</a>
<a href="{{ path('archive', {repo: repo, branch: branch, format: 'tar'}) }}" class="btn btn-mini" title="Download '{{ branch }}' as a TAR archive">TAR</a>
</div>
<a href="{{ path('rss', {repo: repo, branch: branch}) }}" class="rss-icon"><i class="rss"></i></a>
</div>
{% endblock %}
{% endembed %}
{% if results %}
<table class="tree">
<thead>
<tr>
<th width="20%">name</th>
<th width="80%">match</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td><i class="icon-file icon-spaced"></i> <a href="{{ path('blob', {repo: repo, branch: branch, file: result.file}) }}#L{{ result.line }}">{{ result.file }}</a></td>
<td>{{ result.match }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No results found.</p>
{% endif %}
<hr />
{% endblock %}

13
views/searchcommits.twig Normal file
View File

@@ -0,0 +1,13 @@
{% extends 'layout_page.twig' %}
{% set page = 'searchcommits' %}
{% block title %}GitList{% endblock %}
{% block content %}
{% include 'breadcrumb.twig' with {breadcrumbs: [{dir: 'Commits search results', path:''}]} %}
{% include 'commits_list.twig' %}
<hr />
{% endblock %}

View File

@@ -193,7 +193,8 @@ input:focus:required:invalid,textarea:focus:required:invalid,select:focus:requir
.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;}
.form-search{margin:3px 0 0 0;padding:0;}
.search-query{padding:3px;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;font-size:11px;}
.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;}
.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
.form-search label,.form-inline label{display:inline-block;}

View File

@@ -466,13 +466,16 @@ select:focus:required:invalid {
// SEARCH FORM
// -----------
.form-search {
margin: 3px 0 0 0;
padding: 0;
}
.search-query {
padding-right: 14px;
padding-right: 4px \9;
padding-left: 14px;
padding-left: 4px \9; /* IE7-8 doesn't have border-radius, so don't indent the padding */
padding: 3px;
margin-bottom: 0; // remove the default margin on all inputs
.border-radius(14px);
.border-radius(4px);
font-size: 11px;
}