Skip to content
This repository was archived by the owner on Apr 12, 2020. It is now read-only.

Commit 77818f5

Browse files
author
Alexandre Salomé
committed
Merge pull request #7 from gitonomy/feat-tree
Implemented a tree browser
2 parents 370407a + 072f3f3 commit 77818f5

File tree

12 files changed

+216
-21
lines changed

12 files changed

+216
-21
lines changed

src/Gitonomy/Browser/Application.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ public function registerRouting()
9191
->bind('log_ajax')
9292
;
9393

94+
/** Browse repository */
95+
$this
96+
->get('/{repository}/tree/{revision}/path/{path}', 'controller.main:treeAction')
97+
->bind('tree')
98+
->value('revision', 'master')
99+
->assert('revision', '.*')
100+
->value('path', '')
101+
->assert('path', '.*')
102+
;
103+
94104
/** Commit page */
95105
$this
96106
->get('/{repository}/commit/{hash}', 'controller.main:showCommitAction')

src/Gitonomy/Browser/Controller/MainController.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44

55
use Symfony\Component\Routing\Generator\UrlGenerator;
66
use Symfony\Component\HttpFoundation\RedirectResponse;
7+
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
8+
9+
use Gitonomy\Git\Blob;
10+
use Gitonomy\Git\Tree;
11+
use Gitonomy\Git\Exception\ReferenceNotFoundException;
712

813
class MainController
914
{
@@ -49,6 +54,31 @@ public function logAjaxAction(Request $request, $repository)
4954
return $this->twig->render('log_ajax.html.twig', array('log' => $log));
5055
}
5156

57+
public function treeAction($repository, $revision, $path)
58+
{
59+
try {
60+
$commit = $repository->getRevision($revision)->getResolved();
61+
$tree = $commit->getTree();
62+
} catch (ReferenceNotFoundException $e) {
63+
throw new NotFoundHttpException(sprintf('The revision "%s" is not valid', $revision), $e);
64+
}
65+
66+
try {
67+
$element = $tree->resolvePath($path);
68+
} catch (\Exception $e) {
69+
throw new NotFoundHttpException(sprintf('Cannot find path "%s" for current commit "%s"', $path, $commit->getHash()), $e);
70+
}
71+
72+
$template = $element instanceof Blob ? 'browse_blob.html.twig' : 'browse_tree.html.twig';
73+
74+
return $this->twig->render($template, array(
75+
'commit' => $commit,
76+
'element' => $element,
77+
'path' => $path,
78+
'revision' => $revision,
79+
));
80+
}
81+
5282
public function showCommitAction($repository, $hash)
5383
{
5484
return $this->twig->render('commit.html.twig', array(

src/Gitonomy/Browser/Git/Repository.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Gitonomy\Browser\Git;
44

55
use Gitonomy\Git\Repository as BaseRepository;
6-
use Psr\Log\LoggerInterface;
76

87
class Repository extends BaseRepository
98
{
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{% extends "layout.html.twig" %}
2+
3+
{% block content %}
4+
<h3>Code</h3>
5+
{{ git_blob(element, path) }}
6+
{% endblock %}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{% extends "layout.html.twig" %}
2+
3+
{% block content %}
4+
<h3>Browse</h3>
5+
{{ git_tree(element, commit, path, revision)}}
6+
{% endblock %}

src/Gitonomy/Browser/Resources/views/git/default_theme.html.twig

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,10 +178,10 @@
178178
{% set old = change.rangeOldStart %}
179179
{% set new = change.rangeNewStart %}
180180
{%- for x, line in change.lines -%}
181-
<tr class="{{ line[0] == 1 ? 'new' : line[0] == -1 ? 'old' : '' }}">
181+
<tr class="{{ line[0] == 1 ? 'new' : line[0] == -1 ? 'old' }}">
182182
<td class="old">{{ line[0] != 1 ? old : ' ' }}</td>
183183
<td class="new">{{ line[0] != -1 ? new : ' ' }}</td>
184-
<td class="{{ line[0] == 1 ? 'plus' : line[0] == -1 ? 'minus' : '' }} source"><pre>{{ line[1] }}</pre></td>
184+
<td class="{{ line[0] == 1 ? 'plus' : line[0] == -1 ? 'minus' }} source"><pre>{{ line[1] }}</pre></td>
185185
</tr>
186186
{%- if line[0] == 1 -%}
187187
{%- set new = new + 1 -%}
@@ -202,7 +202,7 @@
202202
{% spaceless %}
203203
<a href="{{ git_url(reference) }}">
204204
{% if reference is git_branch %}
205-
<span class="ref branch{{ reference.isRemote ? ' remote' : '' }}">
205+
<span class="ref branch{{ reference.isRemote ? ' remote' }}">
206206
{% elseif reference is git_tag %}
207207
<span class="ref tag">
208208
{% elseif reference is git_stash %}
@@ -215,3 +215,102 @@
215215
</a>
216216
{% endspaceless %}
217217
{% endblock %}
218+
219+
{% block blob_text %}
220+
{% spaceless %}
221+
<pre><code>{{ blob.content }}</code></pre>
222+
{% endspaceless %}
223+
{% endblock %}
224+
225+
{% block blob_image %}
226+
{% spaceless %}
227+
<pre><code>IMAGE</code></pre>
228+
{% endspaceless %}
229+
{% endblock %}
230+
231+
{% block blob_binary %}
232+
{% spaceless %}
233+
<pre><code>BINARY</code></pre>
234+
{% endspaceless %}
235+
{% endblock %}
236+
237+
{% block tree %}
238+
{% spaceless %}
239+
<table class="table table-striped">
240+
{{ git_render('tree_header') }}
241+
<tbody>
242+
{% if parent_path is not sameas(false) %}
243+
<tr>
244+
<td><i class="icon-folder-open"></i></td>
245+
<td>
246+
<a href="{{ path('tree', {revision: revision, path: parent_path}) }}">
247+
..
248+
</a>
249+
</td>
250+
<td></td>
251+
<td></td>
252+
</tr>
253+
{% endif %}
254+
{% for name, data in tree.entries if data[1] is git_tree %}
255+
{{ git_render('tree_row', {
256+
commit: commit,
257+
data: data,
258+
is_dir: true,
259+
name: name,
260+
path: path,
261+
revision: revision,
262+
}) }}
263+
{% endfor %}
264+
{% for name, data in tree.entries if data[1] is not git_tree %}
265+
{{ git_render('tree_row', {
266+
commit: commit,
267+
data: data,
268+
is_dir: false,
269+
name: name,
270+
path: path,
271+
revision: revision,
272+
}) }}
273+
{% endfor %}
274+
</tbody>
275+
</table>
276+
{% endspaceless %}
277+
{% endblock %}
278+
279+
{% block tree_header %}
280+
{% spaceless %}
281+
<thead>
282+
<tr>
283+
<th width="20"></td>
284+
<th>{{ 'table.filename'|trans }}</th>
285+
<th>{{ 'table.date'|trans }}</th>
286+
<th>{{ 'table.last_commit'|trans }}</th>
287+
</tr>
288+
</thead>
289+
{% endspaceless %}
290+
{% endblock %}
291+
292+
{% block tree_row %}
293+
{% spaceless %}
294+
{% set pathLastModification = commit.lastModification(path~'/'~name) %}
295+
<tr>
296+
<td>{% if is_dir is defined and is_dir %}<i class="icon-folder-open"></i>{% endif %}</td>
297+
<td>
298+
<a href="{{ path('tree', {revision: revision, path: (path ~ (path ? '/') ~ name)}) }}">
299+
{{ name }}
300+
</a>
301+
</td>
302+
<td>
303+
{{ pathLastModification.getCommitterDate.format('Y-m-d H:i:s') }}
304+
</td>
305+
<td>
306+
<a href="{{ path('commit', { hash: pathLastModification.hash }) }}">
307+
{{ pathLastModification.fixedShortHash }}
308+
</a>
309+
{{ pathLastModification.shortMessage }}
310+
<small>
311+
({{ pathLastModification.authorName }})
312+
</small>
313+
</td>
314+
</tr>
315+
{% endspaceless %}
316+
{% endblock %}

src/Gitonomy/Browser/Resources/views/layout.html.twig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
<div class="gitonomy-browser">
1212
<h1>
1313
{% if repository|default(false) %}
14-
<a class="project-name" href="{{ path('repository') }}">{{ repository.name }}</a>
14+
<a class="project-name" href="{{ url('repository') }}">{{ repository.name }}</a>
1515
-
1616
{% endif %}
17-
<a href="{{ path('repositories') }}">gitonomy/browser</a>
17+
<a href="{{ url('repositories') }}">gitonomy/browser</a>
1818
</h1>
1919
<div class="gitonomy-browser-content">
2020
{% block content '' %}

src/Gitonomy/Browser/Resources/views/reference.html.twig

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,26 @@
66
<h2>
77
{% if reference is git_branch %}
88
branch {{ reference.name }}
9+
{% set hash = reference.name %}
910
{% elseif reference is git_tag %}
1011
tag {{ reference.name }}
12+
{% set hash = reference.fullname %}
1113
{% elseif reference is git_stash %}
1214
tag {{ reference.name }}
1315
{% else %}
1416
{{ reference.fullname }}
1517
{% endif %}
1618
<div style="float: right">
17-
<form method="POST" action="{{ path('reference_delete', {fullname: reference.fullname}) }}">
19+
<form method="POST" action="{{ url('reference_delete', {fullname: reference.fullname}) }}">
1820
<input type="submit" value="DELETE" />
1921
</form>
2022
</div>
2123
</h2>
22-
{{ git_log(reference.log.setLimit(10), {query_url: path('log_ajax', {fullname: reference.fullname})}) }}
24+
25+
{% if hash is defined %}
26+
<h3>Browse</h3>
27+
<a href="{{ url('tree', {reference: hash }) }}">Browse the repository</a>
28+
{% endif %}
29+
30+
{{ git_log(reference.log.setLimit(10), {query_url: url('log_ajax', {fullname: reference.fullname})}) }}
2331
{% endblock %}
Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
{% extends "layout.html.twig" %}
22

33
{% block content %}
4-
<h3>Branches</h3>
5-
{{ git_branches(repository) }}
4+
{% if repository.references.branches %}
5+
<h3>Branches</h3>
6+
{{ git_branches(repository) }}
7+
{% endif %}
68

7-
<h3>Tags</h3>
8-
{{ git_tags(repository) }}
9+
{% if repository.references.tags %}
10+
<h3>Tags</h3>
11+
{{ git_tags(repository) }}
12+
{% endif %}
13+
14+
<h3>Browse</h3>
15+
<a href="{{ url('tree') }}">Browse the repository</a>
916

1017
<h3>Logs</h3>
11-
{{ git_log(repository.log.setLimit(30), {query_url: path('log_ajax')}) }}
18+
{{ git_log(repository.log.setLimit(30), {query_url: url('log_ajax')}) }}
1219
{% endblock %}

src/Gitonomy/Browser/Resources/views/repository_list.html.twig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
{% block content %}
44
{% for repository in repositories %}
55
<h3>
6-
<a href="{{ path('repository', {repository: repository}) }}">
6+
<a href="{{ url('repository', {repository: repository}) }}">
77
{{ repository }}
88
</a>
99
</h3>

src/Gitonomy/Browser/Twig/GitExtension.php

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,17 @@ public function getTokenParsers()
3838
public function getFunctions()
3939
{
4040
return array(
41-
new \Twig_SimpleFunction('git_repository_name', array($this, 'renderRepositoryName'), array('is_safe' => array('html'))),
4241
new \Twig_SimpleFunction('git_author', array($this, 'renderAuthor'), array('is_safe' => array('html'), 'needs_environment' => true)),
42+
new \Twig_SimpleFunction('git_blob', array($this, 'renderBlob'), array('is_safe' => array('html'), 'needs_environment' => true)),
43+
new \Twig_SimpleFunction('git_branches', array($this, 'renderBranches'), array('is_safe' => array('html'), 'needs_environment' => true)),
4344
new \Twig_SimpleFunction('git_commit_header', array($this, 'renderCommitHeader'), array('is_safe' => array('html'), 'needs_environment' => true)),
4445
new \Twig_SimpleFunction('git_diff', array($this, 'renderDiff'), array('is_safe' => array('html'), 'needs_environment' => true)),
45-
new \Twig_SimpleFunction('git_branches', array($this, 'renderBranches'), array('is_safe' => array('html'), 'needs_environment' => true)),
46-
new \Twig_SimpleFunction('git_tags', array($this, 'renderTags'), array('is_safe' => array('html'), 'needs_environment' => true)),
4746
new \Twig_SimpleFunction('git_log', array($this, 'renderLog'), array('is_safe' => array('html'), 'needs_environment' => true)),
47+
new \Twig_SimpleFunction('git_tree', array($this, 'renderTree'), array('is_safe' => array('html'), 'needs_environment' => true)),
4848
new \Twig_SimpleFunction('git_log_rows', array($this, 'renderLogRows'), array('is_safe' => array('html'), 'needs_environment' => true)),
4949
new \Twig_SimpleFunction('git_render', array($this, 'renderBlock'), array('is_safe' => array('html'), 'needs_environment' => true)),
50+
new \Twig_SimpleFunction('git_repository_name', array($this, 'renderRepositoryName'), array('is_safe' => array('html'))),
51+
new \Twig_SimpleFunction('git_tags', array($this, 'renderTags'), array('is_safe' => array('html'), 'needs_environment' => true)),
5052
new \Twig_SimpleFunction('git_url', array($this, 'getUrl')),
5153
);
5254
}
@@ -138,7 +140,6 @@ public function renderBranches(\Twig_Environment $env, Repository $repository, a
138140
));
139141
}
140142

141-
142143
public function renderTags(\Twig_Environment $env, Repository $repository)
143144
{
144145
return $this->renderBlock($env, 'tags', array(
@@ -160,14 +161,41 @@ public function renderAuthor(\Twig_Environment $env, Commit $commit, array $opti
160161
));
161162
}
162163

164+
public function renderTree(\Twig_Environment $env, Tree $tree, Commit $commit, $path = '', $revision = 'master')
165+
{
166+
return $this->renderBlock($env, 'tree', array(
167+
'tree' => $tree,
168+
'parent_path' => substr($path, 0, strrpos($path, '/')),
169+
'path' => $path,
170+
'revision' => $revision,
171+
'commit' => $commit,
172+
));
173+
}
174+
175+
public function renderBlob($env, Blob $blob, $path = null)
176+
{
177+
if ($blob->isText()) {
178+
$block = 'blob_text';
179+
} else {
180+
$mime = $blob->getMimetype();
181+
if (preg_match("#^image/(png|jpe?g|gif)#", $mime)) {
182+
$block = 'blob_image';
183+
} else {
184+
$block = 'blob_binary';
185+
}
186+
}
187+
188+
return $this->renderBlock($env, $block, array('blob' => $blob));
189+
}
190+
163191
public function addThemes($themes)
164192
{
165193
$themes = reset($themes);
166194
$themes = is_array($themes) ? $themes : array($themes);
167195
$this->themes = array_merge($themes, $this->themes);
168196
}
169197

170-
public function renderBlock(\Twig_Environment $env, $block, $context = array())
198+
public function renderBlock(\Twig_Environment $env, $block, $parameters = array())
171199
{
172200
foreach ($this->themes as $theme) {
173201
if ($theme instanceof \Twig_Template) {
@@ -176,7 +204,7 @@ public function renderBlock(\Twig_Environment $env, $block, $context = array())
176204
$tpl = $env->loadTemplate($theme);
177205
}
178206
if ($tpl->hasBlock($block)) {
179-
return $tpl->renderBlock($block, $context);
207+
return $tpl->renderBlock($block, $parameters);
180208
}
181209
}
182210

tests/Gitonomy/Browser/Tests/Functionnal/ControllerTest.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class ApplicationTest extends WebTestCase
99
{
1010
const TEST_REPOSITORY = '[email protected]:gitonomy/foobar.git';
1111

12-
static public function createRepository()
12+
public static function createRepository()
1313
{
1414
$tmp = sys_get_temp_dir().'gitonomybrowser_foobar';
1515
if (!is_dir($tmp)) {
@@ -45,6 +45,8 @@ public function getPage200Tests()
4545
array('/browser'),
4646
array('/browser/refs/heads/master'),
4747
array('/browser/commit/3c05a60d9522eb438d7be74f4ae51b4bcd0f697f'),
48+
array('/browser/tree/master/path'),
49+
array('/browser/tree/3c05a60d9522eb438d7be74f4ae51b4bcd0f697f/path/composer.json'),
4850
);
4951
}
5052

0 commit comments

Comments
 (0)