mirror of
https://github.com/klaussilveira/gitlist.git
synced 2026-05-07 02:26:16 +02:00
Implementing search feature for trees and commit log
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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-._]+')
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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 %}
|
||||
@@ -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
42
views/search.twig
Normal 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
13
views/searchcommits.twig
Normal 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 %}
|
||||
@@ -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;}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user