home » zplus/clif.git
Author zPlus <zplus@peers.community> 2022-08-05 19:48:53
Committer zPlus <zplus@peers.community> 2022-08-05 19:48:53
Commit 2a5d69c (patch)
Tree 3c66e67
Parent(s)

Add page for showing commits.


commits diff: aa8d46a..2a5d69c
5 files changed, 269 insertions, 23 deletionsdownload


Diffstat
-rw-r--r-- static/css/clif.css 56
-rw-r--r-- templates/repository/commit.html 172
-rw-r--r-- templates/repository/log.html 2
-rw-r--r-- templates/repository/refs.html 2
-rw-r--r-- web.py 60

Diff options
View
Side
Whitespace
Context lines
Inter-hunk lines
+55/-1 M   static/css/clif.css
index 3b51603..9380f26
old size: 6K - new size: 7K
@@ -320,8 +320,62 @@ div.threads {
320 320 .thread .info .tag {
321 321 margin-bottom: 1rem;
322 322 }
323 -
323 +
324 + /* Commit page */
325 + div.commit {
326 + }
327 +
328 + div.commit .message {
329 + margin-top: 2rem;
330 + white-space: pre-wrap;
331 + }
332 +
333 + div.commit .diff {
334 + border: 1px solid #d4d4d4;
335 + border-collapse: collapse;
336 + border-spacing: 0;
337 + font-family: monospace;
338 + font-size: 1rem;
339 + margin-top: 2rem;
340 + width: 100%;
341 + }
342 +
343 + div.commit .diff thead {
344 + background-color: #f7f7f7;
345 + border: 1px solid #d4d4d4;
346 + }
347 +
348 + div.commit .diff td {
349 + padding: .1rem .5rem;
350 + }
351 +
352 + div.commit .diff .header {
353 + background-color: #f0f9ff;
354 + color: darkblue;
355 + }
356 +
357 + div.commit .diff .header td {
358 + padding: .5rem .5rem;
359 + }
360 +
361 + div.commit .diff .lineno {
362 + color: gray;
363 + text-align: center;
364 + width: 0;
365 + }
324 366
367 + div.commit .diff .origin {
368 + width: 0;
369 + }
370 +
371 + div.commit .diff .deletion {
372 + background-color: #ffeef0;
373 + }
374 +
375 + div.commit .diff .insertion {
376 + background-color: #e6ffed;
377 + }
378 +
325 379 /* Alternate background color used when displaying table data */
326 380 .striped > *:nth-child(even) {
327 381 background-color: #f8f8f8;

+172/-0 A   templates/repository/commit.html
index 0000000..39f2ca7
old size: 0B - new size: 7K
new file mode: -rw-r--r--
@@ -0,0 +1,172 @@
1 + {% extends "repository/repository.html" %}
2 +
3 + {% block page_title %}Commit: {{ commit.id }}{% endblock %}
4 +
5 + {% block content %}
6 +
7 + <div class="commit">
8 + <table>
9 + <tbody>
10 + <tr>
11 + <td>
12 + <b>Author</b>
13 + </td>
14 + <td>
15 + {{ commit.author }}
16 + {{ commit_time(commit.author.time, commit.author.offset) }}
17 + </td>
18 + </tr>
19 + <tr>
20 + <td>
21 + <b>Committer</b>
22 + </td>
23 + <td>
24 + {{ commit.committer }}
25 + {{ commit_time(commit.committer.time, commit.committer.offset) }}
26 + </td>
27 + </tr>
28 + <tr>
29 + <td>
30 + <b>Commit ID</b>
31 + </td>
32 + <td>
33 + {{ commit.id }}
34 + </td>
35 + </tr>
36 + <tr>
37 + <td>
38 + <b>Tree</b>
39 + </td>
40 + <td>
41 + <a href="{{ url('tree', repository=repository[:-4], revision=commit.tree.id) }}">{{ commit.tree.id }}</a>
42 + </td>
43 + </tr>
44 + <tr>
45 + <td>
46 + <b>Parent(s)</b>
47 + </td>
48 + <td>
49 + {% for parent in commit.parents %}
50 + <a href="{{ url('commit', repository=repository[:-4], commit_id=parent.id) }}">{{ parent.short_id }}</a>
51 + {% endfor %}
52 + </td>
53 + </tr>
54 + <tr>
55 + <td>
56 + <b>±</b>
57 + </td>
58 + <td>
59 + {{ diff.stats.files_changed }} files changed,
60 + {{ diff.stats.insertions }} insertions,
61 + {{ diff.stats.deletions }} deletions
62 + </td>
63 + </tr>
64 + </tbody>
65 + </table>
66 +
67 + <div class="message">{{ commit.message }}</div>
68 +
69 + {% for patch in diff %}
70 +
71 + <table class="diff">
72 +
73 + {# The following status values are defined in the git_delta_t enum
74 + # in libgit2. See https://github.com/libgit2/libgit2/blob/main/include/git2/diff.h
75 + #}
76 +
77 + {# 1=ADDED (does not exist in old version) #}
78 + {# 2=DELETED (does not exist in new version) #}
79 + {# 3=MODIFIED (content changed between old and new versions) #}
80 + {# 4=RENAMED #}
81 + {# 5=COPIED #}
82 + <thead>
83 + <tr>
84 + <td colspan="4">
85 + -{{ patch.line_stats[2] }}/+{{ patch.line_stats[1] }}
86 +
87 + {% if patch.delta.status == 1 %}
88 + <b title="Added">A</b> {{ patch.delta.new_file.path }}
89 + {% endif %}
90 +
91 + {% if patch.delta.status == 2 %}
92 + <b title="Deleted">D</b> {{ patch.delta.old_file.path }}
93 + {% endif %}
94 +
95 + {% if patch.delta.status == 3 %}
96 + <b title="Modified">M</b> {{ patch.delta.new_file.path }}
97 + {% endif %}
98 +
99 + {% if patch.delta.status == 4 %}
100 + <b title="Renamed">R</b> {{ patch.delta.old_file.path }} -> {{ patch.delta.new_file.path }}
101 + {% endif %}
102 +
103 + {% if patch.delta.status == 5 %}
104 + <b title="Copied">C</b> {{ patch.delta.old_file.path }} {{ patch.delta.new_file.path }}
105 + {% endif %}
106 + </td>
107 + </tr>
108 + <tr>
109 + <td colspan="4">
110 + old size: {{ patch.delta.old_file.size|human_size(B=true) }}
111 + -
112 + new size: {{ patch.delta.new_file.size|human_size(B=true) }}
113 + </td>
114 + </tr>
115 + <tr>
116 + <td colspan="4">
117 + {% if patch.delta.status == 1 %}
118 + new file mode: {{ patch.delta.new_file.mode|filemode }}
119 + {% elif patch.delta.status == 2 %}
120 + deleted file mode: {{ patch.delta.old_file.mode|filemode }}
121 + {% elif patch.delta.old_file.mode != patch.delta.new_file.mode %}
122 + old mode: {{ patch.delta.old_file.mode|filemode }}
123 + <br />
124 + new mode: {{ patch.delta.new_file.mode|filemode }}
125 + {% endif %}
126 + </td>
127 + </tr>
128 + </thead>
129 + <tbody>
130 + {% if patch.delta.is_binary %}
131 + <tr>
132 + <td colspan="4">
133 + <i>Binary file</i>
134 + </td>
135 + </tr>
136 + {% endif %}
137 +
138 + {% for hunk in patch.hunks if not patch.delta.is_binary %}
139 +
140 + <tr class="header">
141 + <td></td>
142 + <td></td>
143 + <td></td>
144 + <td>{{ hunk.header }}</td>
145 + </tr>
146 +
147 + {% for line in hunk.lines %}
148 + <tr class="{{ 'insertion' if line.old_lineno < 0 }} {{ 'deletion' if line.new_lineno < 0 }}">
149 + <td class="lineno">
150 + {% if line.old_lineno >= 0 %}
151 + {{ line.old_lineno }}
152 + {% endif %}
153 + </td>
154 + <td class="lineno">
155 + {% if line.new_lineno >= 0 %}
156 + {{ line.new_lineno }}
157 + {% endif %}
158 + </td>
159 + <td class="origin">{{ line.origin }}</td>
160 + <td class="content">{{ line.content }}</td>
161 + </tr>
162 + {% endfor %}
163 +
164 + {% endfor %}
165 + </tbody>
166 +
167 + </table>
168 +
169 + {% endfor %}
170 + </div>
171 +
172 + {% endblock %}

+1/-1 M   templates/repository/log.html
index 2ddb8f8..2ec71a7
old size: 4K - new size: 4K
@@ -56,7 +56,7 @@
56 56 {% endif %}
57 57 </td>
58 58 <td class="short_id" title="{{ commit.id }}">
59 - {{ commit.short_id }}
59 + <a href="{{ url('commit', repository=repository[:-4], commit_id=commit.id) }}">{{ commit.short_id }}</a>
60 60 </td>
61 61 <td class="message">
62 62 {% if commit.message|length <= 100 %}

+1/-1 M   templates/repository/refs.html
index e2b4594..ddec0d7
old size: 3K - new size: 3K
@@ -25,7 +25,7 @@
25 25 {% endif %}
26 26 </td>
27 27 <td>
28 - [{{ head.commit.short_id }}]
28 + <a href="{{ url('commit', repository=repository[:-4], commit_id=head.commit.id) }}">{{ head.commit.short_id }}</a>
29 29 {{ head.commit.message[:80] }}...
30 30 </td>
31 31 <td>

+40/-20 M   web.py
index 772b5eb..d007ed6
old size: 25K - new size: 25K
@@ -345,18 +345,12 @@ def tree(repository, revision, tree_path=None):
345 345
346 346 if repo.is_empty:
347 347 return template('repository/tree.html',
348 - repository=repository, revision=revision)
349 -
350 - git_object = None
348 + repository=repository, revision=revision, offset=0)
351 349
352 350 try:
353 351 git_object = repo.revparse_single(revision)
354 352 except:
355 - pass
356 -
357 - if not git_object:
358 - return template('repository/tree.html',
359 - repository=repository, revision=revision)
353 + bottle.abort(404)
360 354
361 355 # List all the references.
362 356 # This is used for allowing the user to switch revision with a selector.
@@ -443,6 +437,10 @@ def log(repository, revision):
443 437 repository += '.git'
444 438 repository_path = os.path.join(GITOLITE_REPOSITORIES_ROOT, repository)
445 439
440 + # Read commits
441 + try: commits_offset = int(request.query.get('offset', 0))
442 + except: commits_offset = 0
443 +
446 444 if not os.path.isdir(repository_path):
447 445 bottle.abort(404, 'No repository at this path.')
448 446
@@ -450,18 +448,12 @@ def log(repository, revision):
450 448
451 449 if repo.is_empty:
452 450 return template('repository/log.html',
453 - repository=repository, revision=revision)
454 -
455 - git_object = None
451 + repository=repository, revision=revision, offset=commits_offset)
456 452
457 453 try:
458 454 git_object = repo.revparse_single(revision)
459 455 except:
460 - pass
461 -
462 - if not git_object:
463 - return template('repository/log.html',
464 - repository=repository, revision=revision)
456 + bottle.abort(404)
465 457
466 458 # List all the references.
467 459 # This is used for allowing the user to switch revision with a selector.
@@ -487,10 +479,6 @@ def log(repository, revision):
487 479
488 480 # At this point git_object should be a valid pygit2.GIT_OBJ_COMMIT
489 481
490 - # Read commits
491 - try: commits_offset = int(request.query.get('offset', 0))
492 - except: commits_offset = 0
493 -
494 482 commits = []
495 483 diff = {}
496 484 commit_ith = 0
@@ -533,6 +521,38 @@ def log_change(repository):
533 521 repository=repository,
534 522 revision=revision))
535 523
524 + @bottle.get('/<repository:path>.git/commit/<commit_id>', name='commit')
525 + def commit(repository, commit_id):
526 + """
527 + Show a commit.
528 + """
529 +
530 + repository += '.git'
531 + repository_path = os.path.join(GITOLITE_REPOSITORIES_ROOT, repository)
532 +
533 + if not os.path.isdir(repository_path):
534 + bottle.abort(404, 'No repository at this path.')
535 +
536 + repo = pygit2.Repository(repository_path)
537 +
538 + try:
539 + commit = repo.get(commit_id)
540 + assert commit.type == pygit2.GIT_OBJ_COMMIT
541 + except:
542 + bottle.abort(404, 'Not a valid commit.')
543 +
544 + # Find diff wih parent
545 + if len(commit.parents) > 0:
546 + diff = commit.parents[0].tree.diff_to_tree(commit.tree)
547 + else:
548 + diff = commit.tree.diff_to_tree(swap=True)
549 +
550 + diff.find_similar()
551 +
552 + return template(
553 + 'repository/commit.html',
554 + repository=repository, commit=commit, diff=diff)
555 +
536 556 @bottle.get('/<repository:path>.git/raw/<revision>/<tree_path:path>', name='raw')
537 557 def raw(repository, revision, tree_path):
538 558 """