Added Pygments as a class C dependency, and finished the directory view function in views.py.
- Author
- Vngngdn
- Date
- Sept. 8, 2016, 9:03 p.m.
- Hash
- 289e3c93312b178e3a408ca09ae1295d823a1499
- Parent
- 165943b00b2d6fcfb2f44c9675a33b492f0e7ea7
- Modified files
- DEPENDENCIES.md
- views.py
DEPENDENCIES.md ¶
2 additions and 0 deletions.
View changes Hide changes
1 |
1 |
============ |
2 |
2 |
|
3 |
3 |
Since web apps (and everything web related) are known to suck at dependency handling (which is why we have Bower, NPM, cdnjs, docker, ... (I'll explain sometime somewhere why this is done, and why I don't like it), I've decided to take matters in my own hands; I'll just provide one simple markdown file listing all dependencies in human-readable format. I don't care whether this helps or not, but no harm is done, right? |
4 |
4 |
|
5 |
5 |
Legend |
6 |
6 |
------ |
7 |
7 |
|
8 |
8 |
The dependencies themselves have been ranked with a certain grade. I explain what they mean here: |
9 |
9 |
|
10 |
10 |
* A : This dependency is present inside the app. This will be in the form of ready-to-use source code files. As such, they need no further attention. |
11 |
11 |
* B : This dependency is present inside the app. This will be in the form of an archive file (i.e. .tar.gz), OR this needs additional work to function properly. In these cases, I refer to their documentation which will be available at the location of the files. |
12 |
12 |
* C : This dependency does not come with the app. These are often system packages, which often means (if you're on GNU/Linux) you'll have to search for it in your repositories. Their documentation is your last resort for these if it doesn't work as it should. |
13 |
13 |
|
14 |
14 |
I hope I never will, but when it's necessary, I'll add a D grade, for unreadable, egregious bogus software that will give you all horrible kinds of diseases if you dare to work with it, but are indispensable to make the web app function. Just be happy I don't use it yet. (For example, PHP qualifies as D, so praise [our lord and saviour](https://rms.sexy) I write Python.) |
15 |
15 |
|
16 |
16 |
A |
17 |
17 |
- |
18 |
18 |
|
19 |
19 |
B |
20 |
20 |
- |
21 |
21 |
|
22 |
22 |
C |
23 |
23 |
- |
24 |
24 |
* [GitPython](https://github.com/gitpython-developers/GitPython): Provides a |
25 |
25 |
wrapper to ease Git interaction from Python. |
26 |
26 |
* [PostgreSQL](https://postgresql.org): PostgreSQL is (currently) the only |
27 |
27 |
supported database. |
28 |
28 |
|
+ |
29 |
code. |
+ |
30 |
views.py ¶
17 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.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 |
# First, I list some standard variables that are common for most of the sites of this app. |
28 |
28 |
|
29 |
29 |
def footer_description(): |
30 |
30 |
return "Gitar is a simple web app that allows its users to easily share Git repos in combination with the Django framework." |
31 |
31 |
|
32 |
32 |
def footer_links(): |
33 |
33 |
footer_links = [ |
34 |
34 |
['Source', 'OHGODHELPNOTDONEYET'], |
35 |
35 |
['Personal website', reverse('about-index')], |
36 |
36 |
] |
37 |
37 |
return footer_links |
38 |
38 |
|
39 |
39 |
def standard_context(): |
40 |
40 |
context = { |
41 |
41 |
'materialDesign_color': "blue-grey", |
42 |
42 |
'materialDesign_accentColor': "green", |
43 |
43 |
'navbar_title': "Gitar", |
44 |
44 |
'navbar_backArrow': False, |
45 |
45 |
'footer_title': "Gitar", |
46 |
46 |
'footer_description': footer_description(), |
47 |
47 |
'footer_links': footer_links(), |
48 |
48 |
} |
49 |
49 |
return context |
50 |
50 |
|
51 |
51 |
# From here, the actual views start. |
52 |
52 |
def index(request): |
53 |
53 |
""" The start page of Gitar. |
54 |
54 |
|
55 |
55 |
The goal of this view, is to collect all the available repositories, |
56 |
56 |
including some additional information, such as programming language, |
57 |
57 |
license, description, ... in order to give a fast overview of the most |
58 |
58 |
prominent information. |
59 |
59 |
""" |
60 |
60 |
|
61 |
61 |
# Collecting the available repositories: |
62 |
62 |
# Template: |
63 |
63 |
template = "gitar/index.html" |
64 |
64 |
# Requesting the repositories: |
65 |
65 |
modelRepos = Repository.objects.all() |
66 |
66 |
# From here, we start collecting info about all the repositories: |
67 |
67 |
class BlankRepository: pass # Blank object in which all data will be collected. |
68 |
68 |
repositories = [] |
69 |
69 |
for modelRepo in modelRepos: |
70 |
70 |
repository = BlankRepository() |
71 |
71 |
# TODO: Find a way to add all of modelRepo's fields without having to |
72 |
72 |
# hardcode them. This is prone to errors and is redundant. |
73 |
73 |
repository.name = str(modelRepo) |
74 |
74 |
repository.programmingLanguage = modelRepo.programmingLanguage |
75 |
75 |
repository.license = modelRepo.license |
76 |
76 |
repository.description = RepoInfo.get_description(modelRepo) |
77 |
77 |
|
78 |
78 |
#gitRepo = Repo.init(modelRepo.directory(), bare=True) # Connects to the Git Repo. |
79 |
79 |
# See tests.py, which assures all repositories exist. Tests are handy. |
80 |
80 |
#repository.description = gitRepo.description |
81 |
81 |
# This is mostly personal taste, but I like to show the amount of files. |
82 |
82 |
#repoTree = gitRepo.heads.master.commit.tree |
83 |
83 |
#repository.fileCount = len(repoTree.blobs) # blobs are files. |
84 |
84 |
repositories.append(repository) |
85 |
85 |
# After that, I extend the standard context with the repositories: |
86 |
86 |
context = standard_context() |
87 |
87 |
context['repositories'] = repositories |
88 |
88 |
# And finally, sending everything back. |
89 |
89 |
return render(request, template, context) |
90 |
90 |
|
91 |
91 |
def repositories(request, repositoryName): |
92 |
92 |
# I first form the repository link out the given name. |
93 |
93 |
# TODO: Form repo link out of given name. |
94 |
- | print(repositoryName) |
95 |
- | repository = RepoInfo.get_repository_object(repositoryName) |
96 |
94 |
assert repository.bare # My own repos are always bare. |
97 |
95 |
content = repository.heads.master.commit.tree |
98 |
96 |
|
99 |
97 |
# Out of which I can deduce the files: |
100 |
98 |
files = content.blobs |
101 |
99 |
fileNames = [] |
102 |
100 |
for filee in files: |
103 |
101 |
fileNames.append(filee.name) |
104 |
102 |
template = "gitar/repositories.html" |
105 |
103 |
context = standard_context() |
106 |
104 |
context['files'] = fileNames |
107 |
105 |
|
108 |
106 |
assert len(content.blobs) > 0 |
109 |
107 |
assert len(fileNames) > 0 |
110 |
108 |
return render(request, template, context) |
111 |
109 |
|
112 |
110 |
def path_explorer(request, repository_name, path): |
113 |
111 |
""" Checks whether the given path is a file or a directory, and calls the |
114 |
112 |
appropriate view function accordingly. |
115 |
113 |
""" |
116 |
114 |
repository = RepoInfo.get_repository_object(repository_name) |
117 |
115 |
# From the GitPython documentation: |
118 |
116 |
# You can obtain the tree object of a repository, which is the directory of |
119 |
117 |
# that repo. This tree can be accessed as if it were a native Python list, |
120 |
118 |
# where the elements are the subdirectories and files. So, the idea to |
121 |
119 |
# determine whether a file, or a directory was requested, is simple: |
122 |
120 |
# 1. Split the path with "/" as seperator. |
123 |
121 |
# 2. Replace the current tree variable with the one retrieved from the |
124 |
122 |
# subtree element |
125 |
123 |
# 3. Repeat 2. until all parts of the given path are exhausted. |
126 |
124 |
# If we now still have a tree, we're looking at a directory, so display the |
127 |
125 |
# files (and subdirectories) of this directory. |
128 |
126 |
# Else, if we hit a blob, display the file contents. |
129 |
127 |
path_parts = path.split(sep="/") |
130 |
128 |
# FIXME: If the user gives a "<something>/../<somethingElse>", that should |
131 |
129 |
# become "<something>". Obviously, although I think that's done by default |
132 |
130 |
# already. |
133 |
131 |
directory = repository.heads.master.commit.tree |
134 |
132 |
for i in range(len(path_parts)): |
135 |
133 |
subdirectories = directory.trees |
136 |
134 |
if len(subdirectories) == 0: |
137 |
135 |
# If there's no more subdirectory, and we get here, then that means |
138 |
136 |
# it's a file for sure, because otherwise, the iterator would've |
139 |
137 |
# stopped. |
140 |
138 |
file_blob = directory.blobs[path_parts[i]] |
141 |
139 |
return file_viewer(request, repository_name, file_blob) |
142 |
140 |
else: |
143 |
141 |
directory = subdirectories[path_parts[i]] |
144 |
142 |
# Current state: |
145 |
143 |
# The entire path was traversed, and we kept reaching subdirectories, which |
146 |
144 |
# means that the current directory was requested, and not a file. Thus, |
147 |
145 |
# display the directory. |
148 |
146 |
return directory_view(request, repository_name, directory) |
149 |
147 |
|
150 |
148 |
def directory_view(request, repository_name, path, directory): |
151 |
149 |
""" Collects the given directories's files and subdirectories, and renders a |
152 |
150 |
template to display this data. |
153 |
151 |
""" |
154 |
152 |
|
+ |
153 |
files = directory.blobs |
+ |
154 |
file_names = [] |
+ |
155 |
for ffile in files: |
+ |
156 |
file_names.append(ffile.name) |
+ |
157 |
# Collecting all subdirectories: |
+ |
158 |
subdirectories = directory.trees |
+ |
159 |
subdirectory_names = [] |
+ |
160 |
for subdirectory in subdirectories: |
+ |
161 |
subdirectory_names.append(subdirectory.name) |
+ |
162 |
# Collecting rendering information: |
+ |
163 |
template = "gitar/directory.html" |
+ |
164 |
context = standard_context() |
+ |
165 |
context["files"] = file_names |
+ |
166 |
context["subdirectories"] = subdirectory_names |
+ |
167 |
return render(request, template, context) |
+ |
168 |
|
+ |
169 |
|
155 |
170 |
def file_viewer(request, repository_name, path, ffile): |
156 |
171 |
""" Collects the file contents of the given file path, and returns it to the |
157 |
172 |
template, with the file contents already formatted in HTML using Pygments. |
158 |
173 |
""" |
159 |
174 |