... | ... |
@@ -192,9 +192,12 @@ sub startup { |
192 | 192 |
|
193 | 193 |
# Blob |
194 | 194 |
$r->get('/blob/*rev_file' => template '/blob'); |
195 |
- |
|
195 |
+ |
|
196 | 196 |
# Raw |
197 | 197 |
$r->get('/raw/*rev_file' => template '/raw'); |
198 |
+ |
|
199 |
+ # Blame |
|
200 |
+ $r->get('/blame/*rev_file' => template '/blame'); |
|
198 | 201 |
|
199 | 202 |
# Archive |
200 | 203 |
$r->get('/archive/(*rev).tar.gz' => template '/archive')->to(archive_type => 'tar'); |
... | ... |
@@ -155,6 +155,92 @@ sub authors { |
155 | 155 |
return [sort keys %$authors]; |
156 | 156 |
} |
157 | 157 |
|
158 |
+sub blame { |
|
159 |
+ my ($self, $user, $project, $rev, $file) = @_; |
|
160 |
+ |
|
161 |
+ # Blob |
|
162 |
+ my $hash = $self->path_to_hash($user, $project, $rev, $file, 'blob') |
|
163 |
+ or croak 'Cannot find file'; |
|
164 |
+ |
|
165 |
+ # Git blame |
|
166 |
+ my @cmd = $self->cmd( |
|
167 |
+ $user, |
|
168 |
+ $project, |
|
169 |
+ 'blame', |
|
170 |
+ '--line-porcelain', |
|
171 |
+ $rev, |
|
172 |
+ '--', |
|
173 |
+ $file |
|
174 |
+ ); |
|
175 |
+ open my $fh, '-|', @cmd |
|
176 |
+ or croak "Can't git blame --line-porcelain"; |
|
177 |
+ |
|
178 |
+ # Format lines |
|
179 |
+ my $blame_lines = []; |
|
180 |
+ my $blame_line; |
|
181 |
+ while (my $line = $self->_dec(scalar <$fh>)) { |
|
182 |
+ warn $line; |
|
183 |
+ chomp $line; |
|
184 |
+ |
|
185 |
+ if ($blame_line) { |
|
186 |
+ if ($line =~ /^author +(.+)/) { |
|
187 |
+ $blame_line->{author} = $1; |
|
188 |
+ } |
|
189 |
+ elsif ($line =~ /^author-mail +(.+)/) { |
|
190 |
+ $blame_line->{author_mail} = $1; |
|
191 |
+ } |
|
192 |
+ elsif ($line =~ /^summary +(.+)/) { |
|
193 |
+ $blame_line->{summary} = $1; |
|
194 |
+ } |
|
195 |
+ elsif ($line =~ /^\t(.+)?/) { |
|
196 |
+ my $content = $1; |
|
197 |
+ $content = '' unless defined $content; |
|
198 |
+ $blame_line->{content} = $content; |
|
199 |
+ push @$blame_lines, $blame_line; |
|
200 |
+ $blame_line = undef; |
|
201 |
+ } |
|
202 |
+ } |
|
203 |
+ elsif ($line =~ /^([a-fA-F0-9]{40}) +\d+ +(\d+)/) { |
|
204 |
+ $blame_line = {}; |
|
205 |
+ $blame_line->{commit} = $1; |
|
206 |
+ $blame_line->{line} = $2; |
|
207 |
+ if ($blame_lines->[-1] |
|
208 |
+ && $blame_lines->[-1]{commit} eq $blame_line->{commit}) |
|
209 |
+ { |
|
210 |
+ $blame_line->{before_same_commit} = 1; |
|
211 |
+ } |
|
212 |
+ } |
|
213 |
+ } |
|
214 |
+ |
|
215 |
+ return $blame_lines; |
|
216 |
+} |
|
217 |
+ |
|
218 |
+sub blob { |
|
219 |
+ my ($self, $user, $project, $rev, $file) = @_; |
|
220 |
+ |
|
221 |
+ # Blob |
|
222 |
+ my $hash = $self->path_to_hash($user, $project, $rev, $file, 'blob') |
|
223 |
+ or croak 'Cannot find file'; |
|
224 |
+ my @cmd = $self->cmd( |
|
225 |
+ $user, |
|
226 |
+ $project, |
|
227 |
+ 'cat-file', |
|
228 |
+ 'blob', |
|
229 |
+ $hash |
|
230 |
+ ); |
|
231 |
+ open my $fh, '-|', @cmd |
|
232 |
+ or croak "Can't cat $file, $hash"; |
|
233 |
+ |
|
234 |
+ # Format lines |
|
235 |
+ my $lines =[]; |
|
236 |
+ while (my $line = $self->_dec(scalar <$fh>)) { |
|
237 |
+ chomp $line; |
|
238 |
+ push @$lines, $line; |
|
239 |
+ } |
|
240 |
+ |
|
241 |
+ return $lines; |
|
242 |
+} |
|
243 |
+ |
|
158 | 244 |
sub blob_diffs { |
159 | 245 |
my ($self, $user, $project, $rev1, $rev2, $diff_trees) = @_; |
160 | 246 |
|
... | ... |
@@ -240,32 +326,6 @@ sub blob_diffs { |
240 | 326 |
return $blob_diffs; |
241 | 327 |
} |
242 | 328 |
|
243 |
-sub blob { |
|
244 |
- my ($self, $user, $project, $rev, $file) = @_; |
|
245 |
- |
|
246 |
- # Blob |
|
247 |
- my $hash = $self->path_to_hash($user, $project, $rev, $file, 'blob') |
|
248 |
- or croak 'Cannot find file'; |
|
249 |
- my @cmd = $self->cmd( |
|
250 |
- $user, |
|
251 |
- $project, |
|
252 |
- 'cat-file', |
|
253 |
- 'blob', |
|
254 |
- $hash |
|
255 |
- ); |
|
256 |
- open my $fh, '-|', @cmd |
|
257 |
- or croak "Can't cat $file, $hash"; |
|
258 |
- |
|
259 |
- # Format lines |
|
260 |
- my $lines =[]; |
|
261 |
- while (my $line = $self->_dec(scalar <$fh>)) { |
|
262 |
- chomp $line; |
|
263 |
- push @$lines, $line; |
|
264 |
- } |
|
265 |
- |
|
266 |
- return $lines; |
|
267 |
-} |
|
268 |
- |
|
269 | 329 |
sub blob_is_image { |
270 | 330 |
my ($self, $user, $project, $rev, $file) = @_; |
271 | 331 |
|
... | ... |
@@ -0,0 +1,101 @@ |
1 |
+<% |
|
2 |
+ # API |
|
3 |
+ my $api = gitprep_api; |
|
4 |
+ |
|
5 |
+ # Git |
|
6 |
+ my $git = $self->app->git; |
|
7 |
+ |
|
8 |
+ # Parameters |
|
9 |
+ my $user = param('user'); |
|
10 |
+ my $project = param('project'); |
|
11 |
+ my $rev_file = param('rev_file'); |
|
12 |
+ my ($rev, $file) = $git->parse_rev_path($user, $project, $rev_file); |
|
13 |
+ |
|
14 |
+ # Commit |
|
15 |
+ my $commit = $git->last_change_commit($user, $project, $rev, $file); |
|
16 |
+ |
|
17 |
+ # Authors |
|
18 |
+ my $authors = $git->authors($user, $project, $rev, $file); |
|
19 |
+ |
|
20 |
+ # File size |
|
21 |
+ my $file_size = $git->blob_size($user, $project, $rev, $file); |
|
22 |
+ |
|
23 |
+ # File mode |
|
24 |
+ my $mode = $git->blob_mode($user, $project, $rev, $file); |
|
25 |
+ my $file_type = $git->file_type_long($mode); |
|
26 |
+ |
|
27 |
+ # MIME type |
|
28 |
+ my $mime_type = $git->blob_mime_type($user, $project, $rev, $file); |
|
29 |
+ |
|
30 |
+ # Blame |
|
31 |
+ my $lines = $git->blame($user, $project, $rev, $file); |
|
32 |
+ |
|
33 |
+ # Variables for included template |
|
34 |
+ stash(id => $rev, project => $project, rev => $rev); |
|
35 |
+%> |
|
36 |
+ |
|
37 |
+% layout 'common' , title => "$project/$file at $rev \x{30fb} $user/$project"; |
|
38 |
+ |
|
39 |
+% |
|
40 |
+ %= include '/include/header'; |
|
41 |
+ |
|
42 |
+ <div class="container"> |
|
43 |
+ %= include '/include/project_header'; |
|
44 |
+ %= include '/include/code_menu', display => 'files'; |
|
45 |
+ %= include '/include/page_path', type => 'blob', Path => $file; |
|
46 |
+ |
|
47 |
+ <div class="border-gray" style="margin-bottom:20px"> |
|
48 |
+ <div class="bk-blue-light" style="padding:5px"> |
|
49 |
+ <a style="color:#333;font-weight:bold" href="#" title="<%= $commit->{author_email} %>"><%= $commit->{author_name} %></a> |
|
50 |
+ <span class="muted" title="<%= $commit->{age_string_datetime} %>"><%= $commit->{age_string} %></span> |
|
51 |
+ <a style="color:#666" href="<%= url_for("/$user/$project/commit/$rev") %>"> |
|
52 |
+ <%= $commit->{title} %> |
|
53 |
+ </a> |
|
54 |
+ </div> |
|
55 |
+ <div style="padding:5px"> |
|
56 |
+ <b><%= @$authors %></b> <span class="muted">contributor</span> |
|
57 |
+ </div> |
|
58 |
+ </div> |
|
59 |
+ |
|
60 |
+ <div class="border-gray bk-gray-light" style="padding:5px"> |
|
61 |
+ <div class="row"> |
|
62 |
+ <div class="span7" style="padding-top:5px"> |
|
63 |
+ <i class="icon-file icon-white"></i> |
|
64 |
+ <%= $file_type %> |
|
65 |
+ <span class="muted">|</span> |
|
66 |
+ <%= @$lines %> lines |
|
67 |
+ <span class="muted">|</span> |
|
68 |
+ <%= $file_size %>kb |
|
69 |
+ </div> |
|
70 |
+ <div class="text-right"> |
|
71 |
+ <a class="btn" href="<%= url_for("/$user/$project/raw/$rev/$file") %>">Raw</a> |
|
72 |
+ <a class="btn" href="<%= url_for("/$user/$project/blame/$rev/$file") %>">Normal View</a> |
|
73 |
+ <a class="btn" href="<%= url_for("/$user/$project/commits/$rev/$file") %>">History</a> |
|
74 |
+ </div> |
|
75 |
+ </div> |
|
76 |
+ </div> |
|
77 |
+ % if ($mime_type =~ m#^image/#) { |
|
78 |
+ <div style="background:#ddd;text-align:center;padding-top:30px;padding-bottom:30px;margin-bottom:30px"> |
|
79 |
+ <img type="<%= $mime_type %> |
|
80 |
+ % if (defined $file) { |
|
81 |
+ alt="<%= $file %>" title="<%= $file %>" |
|
82 |
+ % } |
|
83 |
+ src="<%= url_for("/$user/$project/raw/$rev/$file") %>" |
|
84 |
+ /> |
|
85 |
+ </div> |
|
86 |
+ % } elsif ($mime_type =~ m#^text/#) { |
|
87 |
+ <pre class="prettyprint linenums"><% for my $line (@$lines) { %><%= "$line\n" %><% } %></pre> |
|
88 |
+ % } else { |
|
89 |
+ <div style="font-size:16px;background:#ddd;text-align:center;padding-top:30px;padding-bottom:30px;margin-bottom:30px"> |
|
90 |
+ <a href="<%= url_for("/$user/$project/raw/$rev/$file") %>">View raw</a> |
|
91 |
+ </div> |
|
92 |
+ % } |
|
93 |
+ </div> |
|
94 |
+ |
|
95 |
+ %= javascript '/js/google-code-prettify/prettify.js'; |
|
96 |
+ %= javascript begin |
|
97 |
+ // Google prety print |
|
98 |
+ prettyPrint(); |
|
99 |
+ % end |
|
100 |
+ |
|
101 |
+ %= include '/include/footer'; |
... | ... |
@@ -69,7 +69,9 @@ |
69 | 69 |
<%= $file_size %>kb |
70 | 70 |
</div> |
71 | 71 |
<div class="text-right"> |
72 |
- <a class="btn" href="<%= url_for("/$user/$project/raw/$rev/$file") %>">Raw</a><a class="btn" href="<%= url_for("/$user/$project/commits/$rev/$file") %>">History</a> |
|
72 |
+ <a class="btn" href="<%= url_for("/$user/$project/raw/$rev/$file") %>">Raw</a> |
|
73 |
+ <a class="btn" href="<%= url_for("/$user/$project/blame/$rev/$file") %>">Blame</a> |
|
74 |
+ <a class="btn" href="<%= url_for("/$user/$project/commits/$rev/$file") %>">History</a> |
|
73 | 75 |
</div> |
74 | 76 |
</div> |
75 | 77 |
</div> |