gitar

Fix bugs with latest update

Author
Maarten Vangeneugden
Date
Oct. 19, 2017, 3:08 a.m.
Hash
7d9d24f3adedfaf2351e0a8dbd70e5bb30c3f1fb
Parent
0b0c8ac62f4d6f1e41704697f2dbf5580f6e8703
Modified files
templates/gitar/directory.html
urls.py
views.py

templates/gitar/directory.html

24 additions and 19 deletions.

View changes Hide changes
1
1
2
-
{% block title %}{{repository-name}} | Gitar{% endblock title %}
3
-
{% block description %}
+
2
{% block title %}{{ repository_name }} | Gitar{% endblock title %}
+
3
{% block description %}
4
4
{{repository-description}}
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
</div>
10
10
<div class="section">
11
11
    <div class="row">
12
12
        <div class="col hide-on-med-and-down l4">
13
13
            <!-- Add tertiary information such as branches and licensing here.  -->
14
14
            <h3 class="{{mdc}}-text">{{repository-name}}</h3>
15
-
            <h5 class="{{mdc}}-text">{% trans "Description" %}</h5>
+
15
            <h5 class="{{mdc}}-text">{% trans "Description" %}</h5>
16
16
            {{repository-description}}
17
-
            <h5 class="{{mdc}}-text">Branches</h5>
+
17
            <h5 class="{{mdc}}-text">Branches</h5>
18
18
            {% for branch in branches %}
19
19
            <a class="{{mdac}}-text text-accent-3" href="{% url 'gitar-repository' repository-name branch %}">
20
-
                {{branch}}
+
20
                'gitar-path-explorer' repository_name branch %}">
+
21
                {{branch}}
21
22
            </a><br />
22
23
            {% endfor %}
23
24
            <h5 class="{{mdc}}-text">{% trans "Extra information" %}</h5>
24
25
            <div class="chip">
25
26
                {{repository-language}}
26
-
                <i class="material-icons {{mdac}}-text text-accent-3">code</i>
+
27
                <i class="material-icons {{mdac}}-text text-accent-3">code</i>
27
28
            </div><br />
28
29
            <div class="chip">
29
30
                {{repository-license}}
30
-
                <i class="material-icons {{mdac}}-text text-accent-3">copyright</i>
+
31
                <i class="material-icons {{mdac}}-text text-accent-3">copyright</i>
31
32
            </div><br />
32
33
        </div>
33
34
        <div class="col s12 m8 l5">
34
35
            <!-- Main area with links to files and subdirectories -->
35
36
            <table class="highlight">
36
37
                {% if subdirectories %}
37
38
                <thead>
38
39
                    {% for subdirectory in subdirectories %}
39
40
                    <a href="{% url 'gitar-repository' repository-name branch subdirectory.path %}">
40
-
                        <tr>
41
-
                            <th>{{subdirectory.name}}</th>
42
-
                        </tr>
43
-
                    </a>
44
-
                    {% endfor %}
+
41
                        <th>
+
42
                        <a class="{{mdac}}-text text-accent-4" href="{% url 'gitar-path-explorer' repository_name branch subdirectory.path %}">
+
43
                            {{subdirectory.name}}
+
44
                        </a>
+
45
                        </th>
+
46
                    </tr>
+
47
                    {% endfor %}
45
48
                </thead>
46
49
                {% endif %}
47
50
                <tbody>
48
51
                    {% for file in files %}
49
52
                    <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
                        <td>
+
54
                        <a class="{{mdac}}-text text-accent-3" href="{% url 'gitar-path-explorer' repository_name branch file.path %}">
+
55
                            {{file.name}}
+
56
                        </a>
+
57
                        </td>
+
58
                            <td>{{file.commit|truncatechars:6}}</td>
53
59
                        </tr>
54
-
                    </a>
55
-
                    {% endfor %}
+
60
                    {% endfor %}
56
61
                </tbody>
57
62
            </table>
58
63
        </div>
59
64
        <div class="col hide-on-small-only m4 l3">
60
65
            <!-- List of commits on the current branch, chronologically. -->
61
66
            <h3 class="{{mdac}}-text text-accent-3">Commits</h3>
62
67
            {% for commit in commits %}
63
68
            <hr />
64
69
            <a class="{{mdac}}-text text-accent-3" href="{% url 'gitar-commit' repository-name commit.hash">
65
-
                {{commit.hash|truncatechars:8}}
+
70
                {{commit.hash|truncatechars:8}}
66
71
            </a>
67
72
            <span class="{{mdc}}-text text-lighten-2">
68
73
                {% trans "by" %} {{commit.author}}
69
74
            </span><br />
70
75
            {{commit.description|lower|capfirst}}{% if commit.description|last != "." %}.{% endif %}
71
76
            {% endfor %}
72
77
        </div>
73
78
    </div>
74
79
</div>
75
80
{% endwith %}
76
81
{% endblock main %}
77
82

urls.py

1 addition and 1 deletion.

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
24
        url(r'^(?P<repository_name>\w+)/(?P<commit>[0-9a-f]{20})$', views.commit, name='gitar-commit'),
25
25
        url(r'^(?P<repository_name>\w+)/(?P<branch>\w+)$', views.repositories, name='gitar-repository'),
26
26
        url(r'^(?P<repository_name>\w+)/(?P<branch>\w+)/(?P<path>([^/]+/)+)$', views.path_explorer, name='gitar-path-explorer'),
27
-
+
27
28
28
        ]
29
29
# XXX: The URL patterns are a bit error-prone, and assume the repository is not
30
30
# named as if R2-D2 would. For example: a hexadecimal string of 20 characters
31
31
# is most likely a commit hash, but is a perfectly valid branch name, as well
32
32
# as a file AND directory name. But the chance of someone naming his/her branch
33
33
# like that is so unlikely I'd rather have it this way for now.
34
34

views.py

13 additions and 13 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
19
from django.core.urlresolvers import reverse
20
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 commit(request, repository, commit):
94
94
    pass  # TODO
95
95
96
96
def repositories(request, repository_name, branch="master"):
97
97
    # A repo's root is a directory by default, so this will automatically return
98
98
    # a directory view. But still, this is a bit nicer.
99
99
    return path_explorer(request, repository_name, branch, "")
100
100
101
101
def path_explorer(request, repository_name, branch, path):
102
102
    """ Checks whether the given path is a file or a directory, and calls the
103
103
    appropriate view function accordingly.
104
104
    """
105
105
    repository = RepoInfo.get_repository_object(repository_name)
106
106
    # From the GitPython documentation:
107
107
    # You can obtain the tree object of a repository, which is the directory of
108
108
    # that repo. This tree can be accessed as if it were a native Python list,
109
109
    # where the elements are the subdirectories and files. So, the idea to
110
110
    # determine whether a file, or a directory was requested, is simple:
111
111
    # 1. Split the path with "/" as seperator.
112
112
    # 2. Replace the current tree variable with the one retrieved from the
113
113
    # subtree element
114
114
    # 3. Repeat 2. until all parts of the given path are exhausted.
115
115
    # If we now still have a tree, we're looking at a directory, so display the
116
116
    # files (and subdirectories) of this directory.
117
117
    # Else, if we hit a blob, display the file contents.
118
118
    path_parts = path.split(sep="/")
119
119
    # FIXME: This is a bug at the URL regex part that I haven't been able to fix
120
120
    # yet. This serves as a temporary fix:
121
121
    # If the last part of the path is an empty string (which happens when the
122
122
    # last symbol was a '/'), remove that part from the list.
123
123
    # Of course, this is bad monkeypatching, but I suck at regex, so as long as
124
124
    # I don't find the solution, this'll have to do.
125
125
126
126
127
127
    print(path_parts)
128
128
129
129
    if path_parts[len(path_parts)-1] == "":
130
130
        path_parts.pop()
131
131
132
132
    if len(path_parts) == 0:
133
133
        directory = repository.heads[branch].commit.tree
134
134
        return directory_view(request, repository_name, path, directory)
135
-
+
135
136
136
    assert len(path_parts) != 0
137
137
138
138
    # FIXME: If the user gives a "<something>/../<somethingElse>", that should
139
139
    # become "<something>". Obviously, although I think that's done by default
140
140
    # already.
141
141
    directory = repository.heads[branch].commit.tree
142
142
    for i in range(len(path_parts)):
143
143
        subdirectories = directory.trees
144
144
        #if len(subdirectories) == 0:
145
145
            # This can't happen, as this would imply there is a directory inside
146
146
            # a file.
147
147
        #    assert False
148
148
        #else:
149
149
        for subdirectory in subdirectories:
150
150
            if subdirectory.name == path_parts[i]:
151
151
                directory = subdirectory
152
152
                #break  # Useless optimization
153
153
    # When there are no more directories to traverse, check if the last part of
154
154
    # the path is either a file, or a directory:
155
155
    blobs = directory.blobs
156
156
    print(path_parts)
157
157
    last_part = path_parts[len(path_parts)-1]
158
158
    for blob in directory.blobs:
159
159
        print(blob.name)
160
160
        if blob.name == last_part:
161
161
            file_blob = blob
162
162
            print("Returning file view")
163
163
            return file_view(request, repository_name, branch, path, file_blob)
164
164
        else:
165
165
            print("blob name: " + blob.name)
166
166
            print("last part: " + last_part)
167
167
    return directory_view(request, repository_name, branch, path, directory)
168
168
169
169
def directory_view(request, repository_name, branch, path, directory):
170
170
    """ Collects the given directories's files and subdirectories, and renders a
171
171
    template to display this data.
172
172
    """
173
173
174
174
    # Collecting files in this directory
175
175
    repository = RepoInfo.get_repository_object(repository_name)
176
176
    files = []
177
177
    for file in directory.blobs:
178
178
        files.append({
179
179
            name:file.name,
180
-
            path:file.path,
181
-
            commit:FileInfo.last_commit(repository, file).binsha,
182
-
            })
+
180
            "path":file.path,
+
181
            "commit":"lol",#FileInfo.last_commit(repository, file).binsha,
+
182
            })
183
183
    # Collecting commits for this branch
184
184
    commits = []
185
185
    for commit in repository.iter_commits(branch):
186
186
        commits.append({
187
187
            hash:commit.binsha,
188
-
            author:commit.author,
189
-
            description:commit.summary,
190
-
            })
+
188
            "author":commit.author,
+
189
            "description":commit.summary,
+
190
            })
191
191
    # Collecting subdirectories
192
192
    subdirectories = []
193
193
    for subdirectory in directory.trees:
194
194
        subdirectories.append({
195
195
            path:subdirectory.path,
196
-
            name:subdirectory.name,
197
-
            })
+
196
            "name":subdirectory.name,
+
197
            })
198
198
    # Collecting rendering information:
199
199
    template = "gitar/directory.html"
200
200
    context = standard_context()
201
201
    context["files"] = files
202
202
    context["subdirectories"] = subdirectories
203
203
    context["commits"] = commits
204
204
    context["branch"] = branch
205
205
    context["repository-name"] = repository_name
206
-
    context["repository-description"] = repository.description
207
-
    # Collection repo information
+
206
    context["repository_description"] = repository.description
+
207
    # Collection repo information
208
208
    for repo in Repository.objects.all():
209
209
        if str(repo) == repository_name:
210
210
            context["repository-language"] = repo.programmingLanguage
211
-
            context["repository-license"] = repo.license
212
-
            break
+
211
            context["repository_license"] = repo.license
+
212
            break
213
213
    return render(request, template, context)
214
214
215
215
216
216
def file_view(request, repository_name, branch, path, ffile):
217
217
    """ Collects the file contents of the given file path, and returns it to the
218
218
    template, with the file contents already formatted in HTML using Pygments.
219
219
    """
220
220
221
221
    # Turning the file's contents in HTML ready output:
222
222
    raw_file_data = ffile.data_stream.read()
223
223
    html_code = code_to_HTML(raw_file_data, ffile.name)
224
224
    # Collecting rendering information:
225
225
    template = "gitar/file.html"
226
226
    context = standard_context()
227
227
    context["content"] = html_code
228
228
    return render(request, template, context)
229
229
    
230
230