Major additions to repo displaying
The Directory template has been given a visual overhaul, and now fully supports different screen sizes. Furthermore, the amount of data displayed has been increased, and the handling of links in the templates and in the URLConf has been improved.
In the view module, the functions have been adapted so they can provide all the necessary information to the templates.
Next improvements will consist of bugfixes and handling the displaying of files.
- Author
- Maarten 'Vngngdn' Vangeneugden
- Date
- Oct. 19, 2017, 2:39 a.m.
- Hash
- 0b0c8ac62f4d6f1e41704697f2dbf5580f6e8703
- Parent
- ac8c428e67d325522d7d81135b28527241280754
- Modified files
- GitActions/RepoInfo.py
- templates/gitar/directory.html
- templates/gitar/file.html
- urls.py
- views.py
GitActions/RepoInfo.py ¶
20 additions and 0 deletions.
View changes Hide changes
1 |
1 |
Copyright © 2016 Maarten "Vngngdn" Vangeneugden |
2 |
2 |
|
3 |
3 |
This program is free software: you can redistribute it and/or modify |
4 |
4 |
it under the terms of the GNU Affero General Public License as |
5 |
5 |
published by the Free Software Foundation, either version 3 of the |
6 |
6 |
License, or (at your option) any later version. |
7 |
7 |
|
8 |
8 |
This program is distributed in the hope that it will be useful, |
9 |
9 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 |
10 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 |
11 |
GNU Affero General Public License for more details. |
12 |
12 |
|
13 |
13 |
You should have received a copy of the GNU Affero General Public License |
14 |
14 |
along with this program. If not, see https://www.gnu.org/licenses/agpl.html. |
15 |
15 |
""" |
16 |
16 |
|
17 |
17 |
from ..models import Repository |
18 |
18 |
import git |
19 |
19 |
|
20 |
20 |
def get_description(repository): |
21 |
21 |
""" Returns the Git repo description of the given repository. |
22 |
22 |
""" |
23 |
23 |
if isinstance(repository, Repository): |
24 |
24 |
repository = git.Repo(repository.directory_path) |
25 |
25 |
|
26 |
26 |
return repository.description |
27 |
27 |
|
28 |
28 |
def log_message(repository, commit, simple=True): |
29 |
29 |
""" Returns the log message that was attached to the given commit. |
30 |
30 |
|
31 |
31 |
Keyword arguments: |
32 |
32 |
repository -- the repository in which to search |
33 |
33 |
commit -- the specific commit hash |
34 |
34 |
simple -- whether to return a oneliner, or the entire message (default True) |
35 |
35 |
""" |
36 |
36 |
pass |
37 |
37 |
|
38 |
38 |
|
39 |
39 |
def get_repository_object(repository_name): |
40 |
40 |
""" Checks the database for a repository with the same name, and returns a |
41 |
41 |
GitPython Repo object. |
42 |
42 |
|
43 |
43 |
Given the name of the repository, this function will search the database for |
44 |
44 |
a repository whoms name corresponds with the given name. When it found one, |
45 |
45 |
|
46 |
46 |
Keyword arguments: |
47 |
47 |
repository_name -- The name of the repository |
48 |
48 |
""" |
49 |
49 |
# Next line raises a Repository.DoesNotExist exception if not found, so it's |
50 |
50 |
# not necessary to check whether it was found or not. |
51 |
51 |
repository = Repository.objects.get(directory_path__endswith=repository_name+".git") |
52 |
52 |
|
53 |
53 |
return git.Repo(repository.directory_path) |
54 |
54 |
|
55 |
55 |
def get_repository_model_object(repository_name): |
56 |
56 |
""" Functions identical to the get_repository_object, except that this |
57 |
57 |
function returns the Django model representation. |
58 |
58 |
|
59 |
59 |
Keyword arguments: |
60 |
60 |
repository_name -- The name of the repository |
61 |
61 |
""" |
62 |
62 |
return Repository.objects.get(directory_path__endswith=repository_name+".git") |
63 |
63 |
|
64 |
64 |
def read_file(file_blob): |
65 |
65 |
""" Reads the contents of the given file, and returns it in a list of |
66 |
66 |
strings. |
67 |
67 |
|
68 |
68 |
Reading the contents of a file using GitPython is a bit cumbersome. This |
69 |
69 |
function takes care of the hassle, and returns a list of unicode strings, |
70 |
70 |
allowing easy operations on the file's contents. |
71 |
71 |
""" |
72 |
72 |
|
73 |
73 |
file_data_stream = file_blob.data_stream |
74 |
74 |
file_content = file_data_stream.read().decode("utf-8") |
75 |
75 |
file_formatted_content = [] |
76 |
76 |
line = "" |
77 |
77 |
for character in file_content: |
78 |
78 |
if character != "\n": |
79 |
79 |
line = line + character |
80 |
80 |
else: |
81 |
81 |
file_formatted_content.append(line) |
82 |
82 |
line = "" |
83 |
83 |
return file_formatted_content |
84 |
84 |
|
+ |
85 |
def get_branches(repository): |
+ |
86 |
""" Returns all branch objects of the repository. |
+ |
87 |
""" |
+ |
88 |
return repository.heads |
+ |
89 |
|
+ |
90 |
def get_commits_of_all_branches(repository): |
+ |
91 |
""" Returns a dict with the keys being the branch objects, and the values |
+ |
92 |
being their commits. |
+ |
93 |
""" |
+ |
94 |
heads = repository.heads |
+ |
95 |
branches = dict() |
+ |
96 |
for head in heads: |
+ |
97 |
branches[head] = get_commits(repository, head.name) |
+ |
98 |
return branches |
+ |
99 |
def get_commits(repository, branch="master"): |
+ |
100 |
""" Returns all commits of the given repository. |
+ |
101 |
If branch is unspecified, the commits of the master branch are returned. |
+ |
102 |
""" |
+ |
103 |
return repository.iter_commits(branch) |
+ |
104 |
templates/gitar/directory.html ¶
67 additions and 16 deletions.
View changes Hide changes
1 |
1 |
|
2 |
2 |
{% block title %}Gitar | Index page{% endblock title %} |
3 |
- | {% block description %} |
+ |
3 |
{% block description %} |
4 |
4 |
Maarten's Gitar app. Still under heavy development, but maintained with <3 |
5 |
- | {% endblock description %} |
+ |
5 |
{% endblock description %} |
6 |
6 |
{% block main %} |
7 |
7 |
{% with mdac=materialDesign_accentColor %} {# You'll see why this is handy shortly. #} |
8 |
8 |
<div class="section {{ materialDesign_color }} lighten-2"> |
9 |
9 |
<p class="flow-text container white-text"> |
10 |
- | Gitar is a simple web app to easily host Git repositories using the Django framework. |
11 |
- | </p> |
12 |
- | </div> |
13 |
10 |
<div class="container section"> |
14 |
- | |
15 |
- | <ul> |
16 |
- | {% for subdirectory in subdirectories %} |
17 |
- | <li><a href="{{ request.path }}/{{ subdirectory }}">{{ subdirectory }}</a></li> |
18 |
- | {% endfor %} |
19 |
- | {% for file in files %} |
20 |
- | <li><a href="{{ request.path }}{{ file }}">{{ file }}</a></li> |
21 |
- | {% endfor %} |
22 |
- | </ul> |
23 |
- | </div> |
24 |
- | {% endwith %} |
+ |
11 |
<div class="row"> |
+ |
12 |
<div class="col hide-on-med-and-down l4"> |
+ |
13 |
<!-- Add tertiary information such as branches and licensing here. --> |
+ |
14 |
<h3 class="{{mdc}}-text">{{repository-name}}</h3> |
+ |
15 |
<h5 class="{{mdc}}-text">{% trans "Description" %}</h5> |
+ |
16 |
{{repository-description}} |
+ |
17 |
<h5 class="{{mdc}}-text">Branches</h5> |
+ |
18 |
{% for branch in branches %} |
+ |
19 |
<a class="{{mdac}}-text text-accent-3" href="{% url 'gitar-repository' repository-name branch %}"> |
+ |
20 |
{{branch}} |
+ |
21 |
</a><br /> |
+ |
22 |
{% endfor %} |
+ |
23 |
<h5 class="{{mdc}}-text">{% trans "Extra information" %}</h5> |
+ |
24 |
<div class="chip"> |
+ |
25 |
{{repository-language}} |
+ |
26 |
<i class="material-icons {{mdac}}-text text-accent-3">code</i> |
+ |
27 |
</div><br /> |
+ |
28 |
<div class="chip"> |
+ |
29 |
{{repository-license}} |
+ |
30 |
<i class="material-icons {{mdac}}-text text-accent-3">copyright</i> |
+ |
31 |
</div><br /> |
+ |
32 |
</div> |
+ |
33 |
<div class="col s12 m8 l5"> |
+ |
34 |
<!-- Main area with links to files and subdirectories --> |
+ |
35 |
<table class="highlight"> |
+ |
36 |
{% if subdirectories %} |
+ |
37 |
<thead> |
+ |
38 |
{% for subdirectory in subdirectories %} |
+ |
39 |
<a href="{% url 'gitar-repository' repository-name branch subdirectory.path %}"> |
+ |
40 |
<tr> |
+ |
41 |
<th>{{subdirectory.name}}</th> |
+ |
42 |
</tr> |
+ |
43 |
</a> |
+ |
44 |
{% endfor %} |
+ |
45 |
</thead> |
+ |
46 |
{% endif %} |
+ |
47 |
<tbody> |
+ |
48 |
{% for file in files %} |
+ |
49 |
<a href="{% url 'gitar-repository' repository-name branch file.path %}"> |
+ |
50 |
<tr> |
+ |
51 |
<td>{{file.name}}</td> |
+ |
52 |
<td>{{file.commit|truncatechars:6}}</td> |
+ |
53 |
</tr> |
+ |
54 |
</a> |
+ |
55 |
{% endfor %} |
+ |
56 |
</tbody> |
+ |
57 |
</table> |
+ |
58 |
</div> |
+ |
59 |
<div class="col hide-on-small-only m4 l3"> |
+ |
60 |
<!-- List of commits on the current branch, chronologically. --> |
+ |
61 |
<h3 class="{{mdac}}-text text-accent-3">Commits</h3> |
+ |
62 |
{% for commit in commits %} |
+ |
63 |
<hr /> |
+ |
64 |
<a class="{{mdac}}-text text-accent-3" href="{% url 'gitar-commit' repository-name commit.hash"> |
+ |
65 |
{{commit.hash|truncatechars:8}} |
+ |
66 |
</a> |
+ |
67 |
<span class="{{mdc}}-text text-lighten-2"> |
+ |
68 |
{% trans "by" %} {{commit.author}} |
+ |
69 |
</span><br /> |
+ |
70 |
{{commit.description|lower|capfirst}}{% if commit.description|last != "." %}.{% endif %} |
+ |
71 |
{% endfor %} |
+ |
72 |
</div> |
+ |
73 |
</div> |
+ |
74 |
</div> |
+ |
75 |
{% endwith %} |
25 |
76 |
{% endblock main %} |
26 |
77 |
templates/gitar/file.html ¶
3 additions and 2 deletions.
View changes Hide changes
1 |
1 |
|
2 |
2 |
{% block title %}Gitar | Index page{% endblock title %} |
3 |
3 |
|
4 |
4 |
{% block stylesheets %} |
5 |
5 |
<link href="/static/website/materialize/css/google-icons.css" rel="stylesheet" /> |
6 |
6 |
<link href="/static/website/materialize/css/materialize.css" |
7 |
- | rel="stylesheet" media="screen, projection" /> |
8 |
- | <!--<style> |
+ |
7 |
<link rel="stylesheet" href="https://cdn.rawgit.com/tonsky/FiraCode/1.204/distr/fira_code.css"> |
+ |
8 |
<!-- TODO: Download Fira Code stylesheet and serve via the static folder. --> |
+ |
9 |
<!--<style> |
9 |
10 |
td { |
10 |
11 |
padding: 0 0 0 0; |
11 |
12 |
} |
12 |
13 |
pre { |
13 |
14 |
margin-top: 10px; |
14 |
15 |
margin-bottom: 10px; |
15 |
16 |
} |
16 |
17 |
table { |
17 |
18 |
line-height: 0px; |
18 |
19 |
padding-top: 0px; |
19 |
20 |
padding-bottom: 0px; |
20 |
21 |
border-spacing: 0 0; |
21 |
22 |
margin-top: 0px; |
22 |
23 |
margin-bottom: 0px; |
23 |
24 |
} |
24 |
25 |
</style>--> |
25 |
26 |
{# For the syntax coloring of Gitar. TODO for later. #} |
26 |
27 |
<link rel="stylesheet" type="text/css" href="/static/website/syntax.css" /> |
27 |
28 |
<link rel="stylesheet" type="text/css" href="/static/gitar/css/file.css" /> |
28 |
29 |
{% endblock stylesheets %} |
29 |
30 |
|
30 |
31 |
{% block description %} |
31 |
32 |
Vngngdn's Gitar app. Really nothing more to say, except that it FREAKING ROCKS! |
32 |
33 |
{% endblock description %} |
33 |
34 |
{% block main %} |
34 |
35 |
{% with mdac=materialDesign_accentColor %} {# You'll see why this is handy shortly. #} |
35 |
36 |
<div class="section {{ materialDesign_color }} lighten-2"> |
36 |
37 |
<p class="flow-text container white-text"> |
37 |
38 |
Gitar is a simple web app to easily host Git repositories using the Django framework. |
38 |
39 |
</p> |
39 |
40 |
</div> |
40 |
41 |
<div class="container section"> |
41 |
42 |
|
42 |
43 |
<table> |
43 |
44 |
{% for line in content %} |
44 |
45 |
<tr> |
45 |
46 |
<td id="{{ forloop.counter }}" class="line-number"><pre>{{ forloop.counter }}</pre></td> |
46 |
47 |
<td><pre>{{ line|safe }}</pre></td> |
47 |
48 |
</tr> |
48 |
49 |
{% endfor %} |
49 |
50 |
</table> |
50 |
51 |
{% endwith %} |
51 |
52 |
{% endblock main %} |
52 |
53 |
urls.py ¶
9 additions and 2 deletions.
View changes Hide changes
1 |
1 |
Copyright © 2016 Maarten "Vngngdn" Vangeneugden |
2 |
2 |
|
3 |
3 |
This program is free software: you can redistribute it and/or modify |
4 |
4 |
it under the terms of the GNU Affero General Public License as |
5 |
5 |
published by the Free Software Foundation, either version 3 of the |
6 |
6 |
License, or (at your option) any later version. |
7 |
7 |
|
8 |
8 |
This program is distributed in the hope that it will be useful, |
9 |
9 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 |
10 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 |
11 |
GNU Affero General Public License for more details. |
12 |
12 |
|
13 |
13 |
You should have received a copy of the GNU Affero General Public License |
14 |
14 |
along with this program. If not, see https://www.gnu.org/licenses/agpl.html. |
15 |
15 |
""" |
16 |
16 |
|
17 |
17 |
from django.conf.urls import url |
18 |
18 |
|
19 |
19 |
from . import views # Imports the views from the same directory (which is views.py). |
20 |
20 |
|
21 |
21 |
urlpatterns = [ |
22 |
22 |
url(r'^$', views.index, name='gitar-index'), |
23 |
23 |
url(r'^(?P<repository_name>\w+)/$', views.repositories, name='gitar-repository'), |
24 |
- | url(r'^(?P<repository_name>\w+)/(?P<path>([^/]+/)+)$', views.path_explorer, name='gitar-path-explorer'), |
25 |
- | |
+ |
24 |
url(r'^(?P<repository_name>\w+)/(?P<commit>[0-9a-f]{20})$', views.commit, name='gitar-commit'), |
+ |
25 |
url(r'^(?P<repository_name>\w+)/(?P<branch>\w+)$', views.repositories, name='gitar-repository'), |
+ |
26 |
url(r'^(?P<repository_name>\w+)/(?P<branch>\w+)/(?P<path>([^/]+/)+)$', views.path_explorer, name='gitar-path-explorer'), |
+ |
27 |
|
26 |
28 |
] |
27 |
29 |
|
+ |
30 |
# named as if R2-D2 would. For example: a hexadecimal string of 20 characters |
+ |
31 |
# is most likely a commit hash, but is a perfectly valid branch name, as well |
+ |
32 |
# as a file AND directory name. But the chance of someone naming his/her branch |
+ |
33 |
# like that is so unlikely I'd rather have it this way for now. |
+ |
34 |
views.py ¶
51 additions and 23 deletions.
View changes Hide changes
1 |
1 |
Copyright © 2016 Maarten "Vngngdn" Vangeneugden |
2 |
2 |
|
3 |
3 |
This program is free software: you can redistribute it and/or modify |
4 |
4 |
it under the terms of the GNU Affero General Public License as |
5 |
5 |
published by the Free Software Foundation, either version 3 of the |
6 |
6 |
License, or (at your option) any later version. |
7 |
7 |
|
8 |
8 |
This program is distributed in the hope that it will be useful, |
9 |
9 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 |
10 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 |
11 |
GNU Affero General Public License for more details. |
12 |
12 |
|
13 |
13 |
You should have received a copy of the GNU Affero General Public License |
14 |
14 |
along with this program. If not, see https://www.gnu.org/licenses/agpl.html. |
15 |
15 |
""" |
16 |
16 |
|
17 |
17 |
from django.shortcuts import get_object_or_404, render # This allows to render the template with the view here. It's pretty cool and important. |
18 |
18 |
from django.http import HttpResponseRedirect, HttpResponse |
19 |
- | from django.core.urlresolvers import reverse |
20 |
- | from .models import * |
+ |
19 |
from django.core.urlresolvers import reverse |
+ |
20 |
from .models import * |
21 |
21 |
|
22 |
22 |
from .GitActions import RepoInfo |
23 |
23 |
|
24 |
24 |
from git import Repo # GitPython functionality. |
25 |
25 |
import git |
26 |
26 |
|
27 |
27 |
from .syntax import * |
28 |
28 |
|
29 |
29 |
# First, I list some standard variables that are common for most of the sites of this app. |
30 |
30 |
|
31 |
31 |
def footer_description(): |
32 |
32 |
return "Gitar is a simple web app that allows its users to easily share Git repos in combination with the Django framework." |
33 |
33 |
|
34 |
34 |
def footer_links(): |
35 |
35 |
footer_links = [ |
36 |
36 |
#['Source', 'OHGODHELPNOTDONEYET'], |
37 |
37 |
['Personal website', reverse('about-index')], |
38 |
38 |
] |
39 |
39 |
return footer_links |
40 |
40 |
|
41 |
41 |
def standard_context(): |
42 |
42 |
context = { |
43 |
43 |
'materialDesign_color': "blue-grey", |
44 |
44 |
'materialDesign_accentColor': "green", |
45 |
45 |
'navbar_title': "Gitar", |
46 |
46 |
'navbar_backArrow': False, |
47 |
47 |
'footer_title': "Gitar", |
48 |
48 |
'footer_description': footer_description(), |
49 |
49 |
'footer_links': footer_links(), |
50 |
50 |
} |
51 |
51 |
return context |
52 |
52 |
|
53 |
53 |
# From here, the actual views start. |
54 |
54 |
def index(request): |
55 |
55 |
""" The start page of Gitar. |
56 |
56 |
|
57 |
57 |
The goal of this view, is to collect all the available repositories, |
58 |
58 |
including some additional information, such as programming language, |
59 |
59 |
license, description, ... in order to give a fast overview of the most |
60 |
60 |
prominent information. |
61 |
61 |
""" |
62 |
62 |
|
63 |
63 |
# Collecting the available repositories: |
64 |
64 |
# Template: |
65 |
65 |
template = "gitar/index.html" |
66 |
66 |
# Requesting the repositories: |
67 |
67 |
modelRepos = Repository.objects.all() |
68 |
68 |
# From here, we start collecting info about all the repositories: |
69 |
69 |
class BlankRepository: pass # Blank object in which all data will be collected. |
70 |
70 |
repositories = [] |
71 |
71 |
for modelRepo in modelRepos: |
72 |
72 |
repository = BlankRepository() |
73 |
73 |
# TODO: Find a way to add all of modelRepo's fields without having to |
74 |
74 |
# hardcode them. This is prone to errors and is redundant. |
75 |
75 |
repository.name = str(modelRepo) |
76 |
76 |
repository.programmingLanguage = modelRepo.programmingLanguage |
77 |
77 |
repository.license = modelRepo.license |
78 |
78 |
repository.description = RepoInfo.get_description(modelRepo) |
79 |
79 |
|
80 |
80 |
#gitRepo = Repo.init(modelRepo.directory(), bare=True) # Connects to the Git Repo. |
81 |
81 |
# See tests.py, which assures all repositories exist. Tests are handy. |
82 |
82 |
#repository.description = gitRepo.description |
83 |
83 |
# This is mostly personal taste, but I like to show the amount of files. |
84 |
84 |
#repoTree = gitRepo.heads.master.commit.tree |
85 |
85 |
#repository.fileCount = len(repoTree.blobs) # blobs are files. |
86 |
86 |
repositories.append(repository) |
87 |
87 |
# After that, I extend the standard context with the repositories: |
88 |
88 |
context = standard_context() |
89 |
89 |
context['repositories'] = repositories |
90 |
90 |
# And finally, sending everything back. |
91 |
91 |
return render(request, template, context) |
92 |
92 |
|
93 |
93 |
def repositories(request, repository_name): |
94 |
- | # A repo's root is a directory by default, so this will automatically return |
+ |
94 |
pass # TODO |
+ |
95 |
|
+ |
96 |
def repositories(request, repository_name, branch="master"): |
+ |
97 |
# A repo's root is a directory by default, so this will automatically return |
95 |
98 |
# a directory view. But still, this is a bit nicer. |
96 |
99 |
return path_explorer(request, repository_name, "") |
97 |
- | |
+ |
100 |
|
98 |
101 |
def path_explorer(request, repository_name, path): |
99 |
- | """ Checks whether the given path is a file or a directory, and calls the |
+ |
102 |
""" Checks whether the given path is a file or a directory, and calls the |
100 |
103 |
appropriate view function accordingly. |
101 |
104 |
""" |
102 |
105 |
repository = RepoInfo.get_repository_object(repository_name) |
103 |
106 |
# From the GitPython documentation: |
104 |
107 |
# You can obtain the tree object of a repository, which is the directory of |
105 |
108 |
# that repo. This tree can be accessed as if it were a native Python list, |
106 |
109 |
# where the elements are the subdirectories and files. So, the idea to |
107 |
110 |
# determine whether a file, or a directory was requested, is simple: |
108 |
111 |
# 1. Split the path with "/" as seperator. |
109 |
112 |
# 2. Replace the current tree variable with the one retrieved from the |
110 |
113 |
# subtree element |
111 |
114 |
# 3. Repeat 2. until all parts of the given path are exhausted. |
112 |
115 |
# If we now still have a tree, we're looking at a directory, so display the |
113 |
116 |
# files (and subdirectories) of this directory. |
114 |
117 |
# Else, if we hit a blob, display the file contents. |
115 |
118 |
path_parts = path.split(sep="/") |
116 |
119 |
# FIXME: This is a bug at the URL regex part that I haven't been able to fix |
117 |
120 |
# yet. This serves as a temporary fix: |
118 |
121 |
# If the last part of the path is an empty string (which happens when the |
119 |
122 |
# last symbol was a '/'), remove that part from the list. |
120 |
123 |
# Of course, this is bad monkeypatching, but I suck at regex, so as long as |
121 |
124 |
# I don't find the solution, this'll have to do. |
122 |
125 |
|
123 |
126 |
|
124 |
127 |
print(path_parts) |
125 |
128 |
|
126 |
129 |
if path_parts[len(path_parts)-1] == "": |
127 |
130 |
path_parts.pop() |
128 |
131 |
|
129 |
132 |
if len(path_parts) == 0: |
130 |
133 |
directory = repository.heads.master.commit.tree |
131 |
- | return directory_view(request, repository_name, path, directory) |
+ |
134 |
return directory_view(request, repository_name, path, directory) |
132 |
135 |
|
133 |
136 |
assert len(path_parts) != 0 |
134 |
137 |
|
135 |
138 |
# FIXME: If the user gives a "<something>/../<somethingElse>", that should |
136 |
139 |
# become "<something>". Obviously, although I think that's done by default |
137 |
140 |
# already. |
138 |
141 |
directory = repository.heads.master.commit.tree |
139 |
- | for i in range(len(path_parts)): |
+ |
142 |
for i in range(len(path_parts)): |
140 |
143 |
subdirectories = directory.trees |
141 |
144 |
#if len(subdirectories) == 0: |
142 |
145 |
# This can't happen, as this would imply there is a directory inside |
143 |
146 |
# a file. |
144 |
147 |
# assert False |
145 |
148 |
#else: |
146 |
149 |
for subdirectory in subdirectories: |
147 |
150 |
if subdirectory.name == path_parts[i]: |
148 |
151 |
directory = subdirectory |
149 |
152 |
#break # Useless optimization |
150 |
153 |
# When there are no more directories to traverse, check if the last part of |
151 |
154 |
# the path is either a file, or a directory: |
152 |
155 |
blobs = directory.blobs |
153 |
156 |
print(path_parts) |
154 |
157 |
last_part = path_parts[len(path_parts)-1] |
155 |
158 |
for blob in directory.blobs: |
156 |
159 |
print(blob.name) |
157 |
160 |
if blob.name == last_part: |
158 |
161 |
file_blob = blob |
159 |
162 |
print("Returning file view") |
160 |
163 |
return file_view(request, repository_name, path, file_blob) |
161 |
- | else: |
+ |
164 |
else: |
162 |
165 |
print("blob name: " + blob.name) |
163 |
166 |
print("last part: " + last_part) |
164 |
167 |
return directory_view(request, repository_name, path, directory) |
165 |
- | |
+ |
168 |
|
166 |
169 |
def directory_view(request, repository_name, path, directory): |
167 |
- | """ Collects the given directories's files and subdirectories, and renders a |
+ |
170 |
""" Collects the given directories's files and subdirectories, and renders a |
168 |
171 |
template to display this data. |
169 |
172 |
""" |
170 |
173 |
# Collecting all files: |
171 |
- | files = directory.blobs |
172 |
- | file_names = [] |
173 |
- | for ffile in files: |
174 |
- | file_names.append(ffile.name) |
175 |
- | # Collecting all subdirectories: |
176 |
- | subdirectories = directory.trees |
177 |
- | subdirectory_names = [] |
178 |
- | for subdirectory in subdirectories: |
179 |
- | subdirectory_names.append(subdirectory.name) |
180 |
- | # Collecting rendering information: |
+ |
174 |
# Collecting files in this directory |
+ |
175 |
repository = RepoInfo.get_repository_object(repository_name) |
+ |
176 |
files = [] |
+ |
177 |
for file in directory.blobs: |
+ |
178 |
files.append({ |
+ |
179 |
name:file.name, |
+ |
180 |
path:file.path, |
+ |
181 |
commit:FileInfo.last_commit(repository, file).binsha, |
+ |
182 |
}) |
+ |
183 |
# Collecting commits for this branch |
+ |
184 |
commits = [] |
+ |
185 |
for commit in repository.iter_commits(branch): |
+ |
186 |
commits.append({ |
+ |
187 |
hash:commit.binsha, |
+ |
188 |
author:commit.author, |
+ |
189 |
description:commit.summary, |
+ |
190 |
}) |
+ |
191 |
# Collecting subdirectories |
+ |
192 |
subdirectories = [] |
+ |
193 |
for subdirectory in directory.trees: |
+ |
194 |
subdirectories.append({ |
+ |
195 |
path:subdirectory.path, |
+ |
196 |
name:subdirectory.name, |
+ |
197 |
}) |
+ |
198 |
# Collecting rendering information: |
181 |
199 |
template = "gitar/directory.html" |
182 |
200 |
context = standard_context() |
183 |
201 |
context["files"] = file_names |
184 |
- | context["subdirectories"] = subdirectory_names |
185 |
- | return render(request, template, context) |
+ |
202 |
context["subdirectories"] = subdirectories |
+ |
203 |
context["commits"] = commits |
+ |
204 |
context["branch"] = branch |
+ |
205 |
context["repository-name"] = repository_name |
+ |
206 |
context["repository-description"] = repository.description |
+ |
207 |
# Collection repo information |
+ |
208 |
for repo in Repository.objects.all(): |
+ |
209 |
if str(repo) == repository_name: |
+ |
210 |
context["repository-language"] = repo.programmingLanguage |
+ |
211 |
context["repository-license"] = repo.license |
+ |
212 |
break |
+ |
213 |
return render(request, template, context) |
186 |
214 |
|
187 |
215 |
|
188 |
216 |
def file_view(request, repository_name, path, ffile): |
189 |
- | """ Collects the file contents of the given file path, and returns it to the |
+ |
217 |
""" Collects the file contents of the given file path, and returns it to the |
190 |
218 |
template, with the file contents already formatted in HTML using Pygments. |
191 |
219 |
""" |
192 |
220 |
|
193 |
221 |
# Turning the file's contents in HTML ready output: |
194 |
222 |
raw_file_data = ffile.data_stream.read() |
195 |
223 |
html_code = code_to_HTML(raw_file_data, ffile.name) |
196 |
224 |
# Collecting rendering information: |
197 |
225 |
template = "gitar/file.html" |
198 |
226 |
context = standard_context() |
199 |
227 |
context["content"] = html_code |
200 |
228 |
return render(request, template, context) |
201 |
229 |
|
202 |
230 |