renamed gitpub to gitprep
|
1 |
package Gitprep::Main; |
copy gitweblite soruce code
|
2 |
use Mojo::Base 'Mojolicious::Controller'; |
3 |
use File::Basename 'dirname'; |
|
4 |
use Carp 'croak'; |
|
5 | ||
6 |
sub blob { |
|
7 |
my $self = shift; |
|
8 | ||
9 |
# Parameters |
|
10 |
my $project_ns = $self->param('project'); |
|
11 |
my $project = "/$project_ns"; |
|
12 |
my $home_ns = dirname $project_ns; |
|
13 |
my $home = "/$home_ns"; |
|
14 |
my $id_file = $self->param('id_file'); |
|
15 | ||
16 |
# Id and file |
|
17 |
my ($id, $file) = $self->_parse_id_path($project, $id_file); |
|
18 | ||
19 |
# Git |
|
20 |
my $git = $self->app->git; |
|
21 | ||
22 |
# Blob content |
|
23 |
my $bid = $git->id_by_path($project, $id, $file, 'blob') |
|
24 |
or croak 'Cannot find file'; |
|
25 |
my @cmd = ($git->cmd($project), 'cat-file', 'blob', $bid); |
|
26 |
open my $fh, '-|', @cmd |
|
27 |
or croak qq/Couldn't cat "$file", "$bid"/; |
|
28 |
|
|
29 |
# Blob plain |
|
30 |
if ($self->stash('plain')) { |
|
31 |
# Content type |
|
32 |
my $type = $git->blob_contenttype($fh, $file); |
|
33 | ||
34 |
# Convert text/* content type to text/plain |
|
35 |
if ($self->config('prevent_xss') && |
|
36 |
($type =~ m#^text/[a-z]+\b(.*)$# || |
|
37 |
($type =~ m#^[a-z]+/[a-z]\+xml\b(.*)$# && -T $fh))) |
|
38 |
{ |
|
39 |
my $rest = $1; |
|
40 |
$rest = defined $rest ? $rest : ''; |
|
41 |
$type = "text/plain$rest"; |
|
42 |
} |
|
43 | ||
44 |
# File name |
|
45 |
my $file_name = $id; |
|
46 |
if (defined $file) { $file_name = $file } |
|
47 |
elsif ($type =~ m/^text\//) { $file_name .= '.txt' } |
|
48 |
|
|
49 |
# Content |
|
50 |
my $content = do { local $/; <$fh> }; |
|
51 |
my $sandbox = $self->config('prevent_xss') && |
|
52 |
$type !~ m#^(?:text/[a-z]+|image/(?:gif|png|jpeg))(?:[ ;]|$)#; |
|
53 |
my $content_disposition = $sandbox ? 'attachment' : 'inline'; |
|
54 |
$content_disposition .= "; filename=$file_name"; |
|
55 |
|
|
56 |
# Render |
|
57 |
$self->res->headers->content_disposition($content_disposition); |
|
58 |
$self->res->headers->content_type($type); |
|
59 |
$self->render_data($content); |
|
60 |
} |
|
61 |
|
|
62 |
# Blob |
|
63 |
else { |
|
64 |
# MIME type |
|
65 |
my $mimetype = $git->blob_mimetype($fh, $file); |
|
66 |
|
|
67 |
# Redirect to blob-plain if no display MIME type |
|
68 |
if ($mimetype !~ m#^(?:text/|image/(?:gif|png|jpeg)$)# && -B $fh) { |
|
69 |
close $fh; |
|
70 |
my $url = $self->url_for('blob_plain', |
|
71 |
project => $project_ns, id_file => "$id/$file"); |
|
72 |
|
|
73 |
return $self->redirect_to($url); |
|
74 |
} |
|
75 |
|
|
76 |
# Commit |
|
77 |
my $commit = $git->parse_commit($project, $id); |
|
78 | ||
79 |
# Parse line |
|
80 |
my @lines; |
|
81 |
while (my $line = $git->dec(scalar <$fh>)) { |
|
82 |
chomp $line; |
|
83 |
$line = $git->_tab_to_space($line); |
|
84 |
push @lines, $line; |
|
85 |
} |
|
86 |
|
|
87 |
# Render |
|
88 |
$self->render( |
|
89 |
home => $home, |
|
90 |
home_ns => $home_ns, |
|
91 |
project => $project, |
|
92 |
project_ns => $project_ns, |
|
93 |
commit => $commit, |
|
94 |
id => $id, |
|
95 |
file => $file, |
|
96 |
bid => $bid, |
|
97 |
lines => \@lines, |
|
98 |
mimetype => $mimetype |
|
99 |
); |
|
100 |
} |
|
101 |
} |
|
102 | ||
103 |
sub blobdiff { |
|
104 |
my $self = shift; |
|
105 | ||
106 |
# Parameters |
|
107 |
my $project_ns = $self->param('project'); |
|
108 |
my $project = "/$project_ns"; |
|
109 |
my $home_ns = dirname $project_ns; |
|
110 |
my $home = "/$home_ns"; |
|
111 |
my $diff = $self->param('diff'); |
|
112 |
my $file = $self->param('file'); |
|
113 |
my $from_file = $self->param('from-file'); |
|
114 |
$from_file = $file unless defined $from_file; |
|
115 |
my $plain = $self->param('plain'); |
|
116 |
my $from_id; |
|
117 |
my $id; |
|
118 |
if ($diff =~ /\.\./) { ($from_id, $id) = $diff =~ /(.+)\.\.(.+)/ } |
|
119 |
else { $id = $diff } |
|
120 |
|
|
121 |
# Git |
|
122 |
my $git = $self->app->git; |
|
123 | ||
124 |
# Get blob diff (command "git diff") |
|
125 |
open my $fh, '-|', $git->cmd($project), 'diff', '-r', '-M', '-p', |
|
126 |
$from_id, $id, '--', $from_file, $file |
|
127 |
or croak "Open git-diff-tree failed"; |
|
128 |
|
|
129 |
# Blob diff plain |
|
130 |
if ($plain) { |
|
131 |
# Content |
|
132 |
my $content = do { local $/; <$fh> }; |
|
133 |
close $fh; |
|
134 |
|
|
135 |
# Render |
|
136 |
my $content_disposition .= "inline; filename=$file"; |
|
137 |
$self->res->headers->content_disposition($content_disposition); |
|
138 |
$self->res->headers->content_type("text/plain; charset=" . $git->encoding); |
|
139 |
$self->render(data => $content); |
|
140 |
} |
|
141 |
|
|
142 |
# Blob diff |
|
143 |
else { |
|
144 |
# Lines |
|
145 |
my @lines = map { $git->dec($_) } <$fh>; |
|
146 |
close $fh; |
|
147 |
my $lines = $self->_parse_blobdiff_lines(\@lines); |
|
148 |
|
|
149 |
# Commit |
|
150 |
my $commit = $git->parse_commit($project, $id); |
|
151 |
|
|
152 |
# Render |
|
153 |
$self->render( |
|
154 |
'/blobdiff', |
|
155 |
home => $home, |
|
156 |
home_ns => $home_ns, |
|
157 |
project => $project, |
|
158 |
project_ns => $project_ns, |
|
159 |
id => $id, |
|
160 |
from_id => $from_id, |
|
161 |
file => $file, |
|
162 |
from_file => $from_file, |
|
163 |
commit => $commit, |
|
164 |
lines => $lines |
|
165 |
); |
|
166 |
} |
|
167 |
} |
|
168 | ||
169 |
sub commit { |
|
170 |
my $self = shift; |
|
171 | ||
172 |
# Parameters |
|
173 |
my $project_ns = $self->param('project'); |
|
174 |
my $project = "/$project_ns"; |
|
175 |
my $home_ns = dirname $project_ns; |
|
176 |
my $home = "/$home_ns"; |
|
177 |
my $id = $self->param('id'); |
|
178 |
|
|
179 |
# Git |
|
180 |
my $git = $self->app->git; |
|
181 | ||
182 |
# Commit |
|
183 |
my $commit = $git->parse_commit($project, $id); |
|
184 |
my $committer_date |
|
185 |
= $git->parse_date($commit->{committer_epoch}, $commit->{committer_tz}); |
|
186 |
my $author_date |
|
187 |
= $git->parse_date($commit->{author_epoch}, $commit->{author_tz}); |
|
188 |
$commit->{author_date} = $git->timestamp($author_date); |
|
189 |
$commit->{committer_date} = $git->timestamp($committer_date); |
|
190 |
|
|
191 |
# References |
|
192 |
my $refs = $git->references($project); |
|
193 |
|
|
194 |
# Diff tree |
|
195 |
my $parent = $commit->{parent}; |
|
196 |
my $parents = $commit->{parents}; |
|
197 |
my $difftrees = $git->difftree($project, $commit->{id}, $parent, $parents); |
|
198 |
|
|
199 |
# Render |
|
200 |
$self->render( |
|
201 |
home => $home, |
|
202 |
home_ns => $home_ns, |
|
203 |
project => $project, |
|
204 |
project_ns => $project_ns, |
|
205 |
id => $id, |
|
206 |
commit => $commit, |
|
207 |
refs => $refs, |
|
208 |
difftrees => $difftrees, |
|
209 |
); |
|
210 |
} |
|
211 | ||
212 |
sub commitdiff { |
|
213 |
my $self = shift; |
|
214 |
|
|
215 |
# Paramters |
|
216 |
my $project_ns = $self->param('project'); |
|
217 |
my $project = "/$project_ns"; |
|
218 |
my $home_ns = dirname $project_ns; |
|
219 |
my $home = "/$home_ns"; |
|
220 |
my $diff = $self->param('diff'); |
|
221 |
my ($from_id, $id) = $diff =~ /(.+)\.\.(.+)/; |
|
222 |
$id = $diff unless defined $id; |
|
223 |
|
|
224 |
# Git |
|
225 |
my $git = $self->app->git; |
|
226 |
|
|
227 |
# Commit |
|
228 |
my $commit = $git->parse_commit($project, $id) |
|
229 |
or croak 'Unknown commit object'; |
|
230 |
my $author_date |
|
231 |
= $git->parse_date($commit->{author_epoch}, $commit->{author_tz}); |
|
232 |
my $committer_date |
|
233 |
= $git->parse_date($commit->{committer_epoch}, $commit->{committer_tz}); |
|
234 |
$commit->{author_date} = $git->timestamp($author_date); |
|
235 |
$commit->{committer_date} = $git->timestamp($committer_date); |
|
236 |
$from_id = $commit->{parent} unless defined $from_id; |
|
237 |
|
|
238 |
# Plain text |
|
239 |
if ($self->param('plain')) { |
|
240 |
# Get blob diffs (command "git diff-tree") |
|
241 |
my @cmd = ($git->cmd($project), 'diff-tree', '-r', '-M', |
|
242 |
'-p', $from_id, $id, '--'); |
|
243 |
open my $fh, '-|', @cmd |
|
244 |
or croak 'Open git-diff-tree failed'; |
|
245 | ||
246 |
# Content |
|
247 |
my $content = do { local $/; <$fh> }; |
|
248 |
my $content_disposition .= "inline; filename=$id"; |
|
249 |
|
|
250 |
# Render |
|
251 |
$self->res->headers->content_disposition($content_disposition); |
|
252 |
$self->res->headers->content_type("text/plain;charset=" . $git->encoding); |
|
253 |
$self->render_data($content); |
|
254 |
} |
|
255 |
|
|
256 |
# HTML |
|
257 |
else { |
|
258 |
|
|
259 |
# Diff tree |
|
260 |
my $difftrees = $git->difftree($project, |
|
261 |
$id, $commit->{parent}, $commit->{parents}); |
|
262 |
|
|
263 |
# Get blob diffs (command "git diff-tree") |
|
264 |
my @cmd = ($git->cmd($project), 'diff-tree', '-r', '-M', |
|
265 |
'--no-commit-id', '--patch-with-raw', $from_id, $id, '--'); |
|
266 |
open my $fh, '-|', @cmd |
|
267 |
or croak 'Open git-diff-tree failed'; |
|
268 | ||
269 |
# Parse output |
|
270 |
my @blobdiffs; |
|
271 |
while (my $line = $git->dec(scalar <$fh>)) { |
|
272 |
|
|
273 |
# Parse line |
|
274 |
chomp $line; |
|
275 |
my $diffinfo = $git->parse_difftree_raw_line($line); |
|
276 |
my $from_file = $diffinfo->{from_file}; |
|
277 |
my $file = $diffinfo->{to_file}; |
|
278 |
|
|
279 |
# Get blobdiff (command "git diff-tree") |
|
280 |
my @cmd = ($git->cmd($project), 'diff-tree', '-r', '-M', '-p', |
|
281 |
$from_id, $id, '--', (defined $from_file ? $from_file : ()), $file); |
|
282 |
open my $fh_blobdiff, '-|', @cmd |
|
283 |
or croak 'Open git-diff-tree failed'; |
|
284 |
my @lines = map { $git->dec($_) } <$fh>; |
|
285 |
close $fh_blobdiff; |
|
286 |
my $blobdiff = { |
|
287 |
file => $file, |
|
288 |
from_file => $from_file, |
|
289 |
lines => $self->_parse_blobdiff_lines(\@lines) |
|
290 |
}; |
|
291 |
|
|
292 |
# Status |
|
293 |
for my $difftree (@$difftrees) { |
|
294 |
if ($difftree->{to_file} eq $file) { |
|
295 |
$blobdiff->{status} = $difftree->{status}; |
|
296 |
last; |
|
297 |
} |
|
298 |
} |
|
299 |
|
|
300 |
push @blobdiffs, $blobdiff; |
|
301 |
} |
|
302 | ||
303 |
# References |
|
304 |
my $refs = $git->references($project); |
|
305 |
|
|
306 |
# Render |
|
307 |
$self->render( |
|
308 |
'commitdiff', |
|
309 |
home => $home, |
|
310 |
home_ns => $home_ns, |
|
311 |
project => $project, |
|
312 |
project_ns => $project_ns, |
|
313 |
from_id => $from_id, |
|
314 |
id => $id, |
|
315 |
commit => $commit, |
|
316 |
difftrees => $difftrees, |
|
317 |
blobdiffs => \@blobdiffs, |
|
318 |
refs => $refs |
|
319 |
); |
|
320 |
} |
|
321 |
} |
|
322 | ||
323 |
sub home { |
|
324 |
my $self = shift; |
|
325 | ||
Dipslay users in home page
|
326 |
my $rep_home = '/gitpub'; |
327 |
my @users = qw/kimoto ken/; |
|
copy gitweblite soruce code
|
328 | |
Dipslay users in home page
|
329 |
$self->render(users => \@users); |
330 |
} |
|
copy gitweblite soruce code
|
331 | |
332 |
sub heads { |
|
333 |
my $self = shift; |
|
334 |
|
|
335 |
# Parameters |
|
336 |
my $project_ns = $self->param('project'); |
|
337 |
my $project = "/$project_ns"; |
|
338 |
my $home_ns = dirname $project_ns; |
|
339 |
my $home = "/$home_ns"; |
|
340 |
|
|
341 |
# Git |
|
342 |
my $git = $self->app->git; |
|
343 |
|
|
344 |
# Ref names |
|
345 |
my $heads = $git->heads($project); |
|
346 |
|
|
347 |
# Render |
|
348 |
$self->render( |
|
349 |
home => $home, |
|
350 |
home_ns => $home_ns, |
|
351 |
project => $project, |
|
352 |
project_ns => $project_ns, |
|
353 |
heads => $heads, |
|
354 |
); |
|
355 |
} |
|
356 | ||
357 |
sub log { |
|
358 |
my ($self, %opt) = @_; |
|
359 | ||
360 |
# Parameters |
|
361 |
my $project_ns = $self->param('project'); |
|
362 |
my $project = "/$project_ns"; |
|
363 |
my $home_ns = dirname $project_ns; |
|
364 |
my $home = "/$home_ns"; |
|
365 |
my $id = $self->param('id'); |
|
366 |
my $page = $self->param('page'); |
|
367 |
$page = 0 if !defined $page; |
|
368 |
my $short = $self->param('short'); |
|
369 |
|
|
370 |
# Git |
|
371 |
my $git = $self->app->git; |
|
372 |
|
|
373 |
# Commit |
|
374 |
my $commit = $git->parse_commit($project, $id); |
|
375 |
|
|
376 |
# Commits |
|
377 |
my $page_count = $short ? 50 : 20; |
|
378 |
my $commits = $git->parse_commits( |
|
379 |
$project, $commit->{id},$page_count, $page_count * $page); |
|
380 |
for my $commit (@$commits) { |
|
381 |
my $author_date |
|
382 |
= $git->parse_date($commit->{author_epoch}, $commit->{author_tz}); |
|
383 |
$commit->{author_date} = $git->timestamp($author_date); |
|
384 |
} |
|
385 |
|
|
386 |
# References |
|
387 |
my $refs = $git->references($project); |
|
388 | ||
389 |
# Render |
|
390 |
$self->stash->{action} = 'shortlog' if $short; |
|
391 |
$self->render( |
|
392 |
home => $home, |
|
393 |
home_ns => $home_ns, |
|
394 |
project => $project, |
|
395 |
project_ns => $project_ns, |
|
396 |
id => $id, |
|
397 |
commits => $commits, |
|
398 |
refs => $refs, |
|
399 |
page => $page, |
|
400 |
page_count => $page_count |
|
401 |
); |
|
402 |
}; |
|
403 | ||
Fixed repositories page
|
404 |
has 'root' => '/gitpub'; |
405 | ||
improved repository page des...
|
406 |
sub _root_ns { |
407 |
my $self = shift; |
|
408 |
|
|
409 |
my $root = $self->root; |
|
410 |
$root =~ s/^\///; |
|
411 |
|
|
412 |
return $root; |
|
413 |
} |
|
414 | ||
415 |
sub repository { |
|
416 |
my $self = shift; |
|
417 |
|
|
418 |
# Parameters |
|
419 |
my $user = $self->param('user'); |
|
420 |
my $repository = $self->param('repository'); |
|
421 |
my $root_ns = $self->_root_ns; |
|
422 |
|
|
423 |
my $project_ns = "$root_ns/$user/$repository.git"; |
|
424 |
my $project = "/$project_ns"; |
|
425 |
my $home_ns = dirname $project_ns; |
|
426 |
my $home = "/$home_ns"; |
|
427 |
my $id_dir = $self->param('id_dir') || 'master/'; |
|
428 | ||
429 |
# Id and directory |
|
430 |
my ($id, $dir) = $self->_parse_id_path($project, $id_dir); |
|
431 | ||
432 |
# Git |
|
433 |
my $git = $self->app->git; |
|
434 |
|
|
435 |
# Tree id |
|
436 |
my $tid; |
|
437 |
my $commit = $git->parse_commit($project, $id); |
|
438 |
unless (defined $tid) { |
|
439 |
if (defined $dir && $dir ne '') { |
|
440 |
$tid = $git->id_by_path($project, $id, $dir, 'tree'); |
|
441 |
} |
|
442 |
else { $tid = $commit->{tree} } |
|
443 |
} |
|
444 |
$self->render_not_found unless defined $tid; |
|
445 | ||
446 |
# Get tree (command "git ls-tree") |
|
447 |
my @entries = (); |
|
448 |
my $show_sizes = 0; |
|
449 |
open my $fh, '-|', $git->cmd($project), 'ls-tree', '-z', |
|
450 |
($show_sizes ? '-l' : ()), $tid |
|
451 |
or croak 'Open git-ls-tree failed'; |
|
452 |
local $/ = "\0"; |
|
453 |
@entries = map { chomp; $git->dec($_) } <$fh>; |
|
454 |
close $fh |
|
455 |
or croak 404, "Reading tree failed"; |
|
456 |
|
|
457 |
# Parse tree |
|
458 |
my @trees; |
|
459 |
for my $line (@entries) { |
|
460 |
my $tree = $git->parse_ls_tree_line($line, -z => 1, -l => $show_sizes); |
|
461 |
$tree->{mode_str} = $git->_mode_str($tree->{mode}); |
|
462 |
push @trees, $tree; |
|
463 |
} |
|
464 |
|
|
465 |
# References |
|
466 |
my $refs = $git->references($project); |
|
467 |
|
|
468 |
# Render |
|
469 |
$self->render( |
|
470 |
home => $home, |
|
471 |
home_ns => $home_ns, |
|
472 |
project => $project, |
|
473 |
project_ns => $project_ns, |
|
474 |
dir => $dir, |
|
475 |
id => $id, |
|
476 |
tid => $tid, |
|
477 |
commit => $commit, |
|
478 |
trees => \@trees, |
|
479 |
refs => $refs |
|
480 |
); |
|
481 |
} |
|
482 | ||
Fixed repositories page
|
483 |
sub repositories { |
484 |
my $self = shift; |
|
485 | ||
486 |
my $root = $self->root; |
|
Fixed repositories page
|
487 |
my $user = $self->param('user'); |
Fixed repositories page
|
488 |
|
Fixed repositories page
|
489 |
# Repositories |
490 |
my $reps = $self->app->git->repositories("/$root/$user"); |
|
Fixed repositories page
|
491 |
|
492 |
# Render |
|
Fixed repositories page
|
493 |
$self->render(reps => $reps); |
Fixed repositories page
|
494 |
} |
495 | ||
copy gitweblite soruce code
|
496 |
sub snapshot { |
497 |
my $self = shift; |
|
498 | ||
499 |
# Parameter |
|
500 |
my $project_ns = $self->param('project'); |
|
501 |
my $project = "/$project_ns"; |
|
502 |
my $home_ns = dirname $project_ns; |
|
503 |
my $home = "/$home_ns"; |
|
504 |
my $id = $self->param('id'); |
|
505 |
|
|
506 |
# Git |
|
507 |
my $git = $self->app->git; |
|
508 | ||
509 |
# Object type |
|
510 |
my $type = $git->object_type($project, "$id^{}"); |
|
511 |
if (!$type) { croak 404, 'Object does not exist' } |
|
512 |
elsif ($type eq 'blob') { croak 400, 'Object is not a tree-ish' } |
|
513 |
|
|
514 |
my ($name, $prefix) = $git->snapshot_name($project, $id); |
|
515 |
my $file = "$name.tar.gz"; |
|
516 |
my $cmd = $self->_quote_command( |
|
517 |
$git->cmd($project), 'archive', "--format=tar", "--prefix=$prefix/", $id |
|
518 |
); |
|
519 |
$cmd .= ' | ' . $self->_quote_command('gzip', '-n'); |
|
520 | ||
521 |
$file =~ s/(["\\])/\\$1/g; |
|
522 | ||
523 |
open my $fh, '-|', $cmd |
|
524 |
or croak 'Execute git-archive failed'; |
|
525 |
|
|
526 |
# Write chunk |
|
527 |
$self->res->headers->content_type('application/x-tar'); |
|
528 |
$self->res->headers->content_disposition(qq/attachment; filename="$file"/); |
|
529 |
my $cb; |
|
530 |
$cb = sub { |
|
531 |
my $c = shift; |
|
532 |
my $size = 500 * 1024; |
|
533 |
my $length = sysread($fh, my $buffer, $size); |
|
534 |
unless (defined $length) { |
|
535 |
close $fh; |
|
536 |
undef $cb; |
|
537 |
return; |
|
538 |
} |
|
539 |
$c->write_chunk($buffer, $cb); |
|
540 |
}; |
|
541 |
$self->$cb; |
|
542 |
} |
|
543 | ||
544 |
sub summary { |
|
545 |
my $self = shift; |
|
546 |
|
|
547 |
# Parameters |
|
548 |
my $project_ns = $self->param('project'); |
|
549 |
my $project = "/$project_ns"; |
|
550 |
my $home_ns = dirname $project_ns; |
|
551 |
my $home = "/$home_ns"; |
|
552 |
|
|
553 |
# Git |
|
554 |
my $git = $self->app->git; |
|
555 |
|
|
556 |
# HEAd commit |
|
557 |
my $project_description = $git->project_description($project); |
|
558 |
my $project_owner = $git->project_owner($project); |
|
559 |
my $head_commit = $git->parse_commit($project, 'HEAD'); |
|
560 |
my $committer_date |
|
561 |
= $git->parse_date($head_commit->{committer_epoch}, $head_commit->{committer_tz}); |
|
562 |
my $last_change = $git->timestamp($committer_date); |
|
563 |
my $head_id = $head_commit->{id}; |
|
564 |
my $urls = $git->project_urls($project); |
|
565 |
|
|
566 |
# Commits |
|
567 |
my $commit_count = 20; |
|
568 |
my $commits = $head_id ? $git->parse_commits($project, $head_id, $commit_count) : (); |
|
569 | ||
570 |
# References |
|
571 |
my $refs = $git->references($project); |
|
572 |
|
|
573 |
# Tags |
|
574 |
my $tag_count = 20; |
|
575 |
my $tags = $git->tags($project, $tag_count - 1); |
|
576 | ||
577 |
# Heads |
|
578 |
my $head_count = 20; |
|
579 |
my $heads = $git->heads($project, $head_count - 1); |
|
580 |
|
|
581 |
# Render |
|
582 |
$self->render( |
|
583 |
home => $home, |
|
584 |
home_ns => $home_ns, |
|
585 |
project => $project, |
|
586 |
project_ns => $project_ns, |
|
587 |
project_description => $project_description, |
|
588 |
project_owner => $project_owner, |
|
589 |
last_change => $last_change, |
|
590 |
urls => $urls, |
|
591 |
commits => $commits, |
|
592 |
tags => $tags, |
|
593 |
head_id => $head_id, |
|
594 |
heads => $heads, |
|
595 |
refs => $refs, |
|
596 |
commit_count => $commit_count, |
|
597 |
tag_count => $tag_count, |
|
598 |
head_count => $head_count |
|
599 |
); |
|
600 |
} |
|
601 | ||
602 |
sub tag { |
|
603 |
my $self = shift; |
|
604 |
|
|
605 |
# Parameters |
|
606 |
my $project_ns = $self->param('project'); |
|
607 |
my $project = "/$project_ns"; |
|
608 |
my $home_ns = dirname $project_ns; |
|
609 |
my $home = "/$home_ns"; |
|
610 |
my $id = $self->param('id'); |
|
611 |
|
|
612 |
# Git |
|
613 |
my $git = $self->app->git; |
|
614 |
|
|
615 |
# Ref names |
|
616 |
my $tag = $git->parse_tag($project, $id); |
|
617 |
my $author_date |
|
618 |
= $git->parse_date($tag->{author_epoch}, $tag->{author_tz}); |
|
619 |
$tag->{author_date} = $git->timestamp($author_date); |
|
620 |
|
|
621 |
# Render |
|
622 |
$self->render( |
|
623 |
home => $home, |
|
624 |
home_ns => $home_ns, |
|
625 |
project => $project, |
|
626 |
project_ns => $project_ns, |
|
627 |
tag => $tag, |
|
628 |
); |
|
629 |
} |
|
630 | ||
631 |
sub tags { |
|
632 |
my $self = shift; |
|
633 |
|
|
634 |
# Parameters |
|
635 |
my $project_ns = $self->param('project'); |
|
636 |
my $project = "/$project_ns"; |
|
637 |
my $home_ns = dirname $project_ns; |
|
638 |
my $home = "/$home_ns"; |
|
639 |
|
|
640 |
# Git |
|
641 |
my $git = $self->app->git; |
|
642 |
|
|
643 |
# Ref names |
|
644 |
my $tags = $git->tags($project); |
|
645 |
|
|
646 |
# Render |
|
647 |
$self->render( |
|
648 |
home => $home, |
|
649 |
home_ns => $home_ns, |
|
650 |
project => $project, |
|
651 |
project_ns => $project_ns, |
|
652 |
tags => $tags, |
|
653 |
); |
|
654 |
} |
|
655 | ||
656 |
sub tree { |
|
657 |
my $self = shift; |
|
658 |
|
|
659 |
# Parameters |
|
660 |
my $project_ns = $self->param('project'); |
|
661 |
my $project = "/$project_ns"; |
|
662 |
my $home_ns = dirname $project_ns; |
|
663 |
my $home = "/$home_ns"; |
|
664 |
my $id_dir = $self->param('id_dir'); |
|
665 | ||
666 |
# Id and directory |
|
667 |
my ($id, $dir) = $self->_parse_id_path($project, $id_dir); |
|
668 | ||
669 |
# Git |
|
670 |
my $git = $self->app->git; |
|
671 |
|
|
672 |
# Tree id |
|
673 |
my $tid; |
|
674 |
my $commit = $git->parse_commit($project, $id); |
|
675 |
unless (defined $tid) { |
|
676 |
if (defined $dir && $dir ne '') { |
|
677 |
$tid = $git->id_by_path($project, $id, $dir, 'tree'); |
|
678 |
} |
|
679 |
else { $tid = $commit->{tree} } |
|
680 |
} |
|
681 |
$self->render_not_found unless defined $tid; |
|
682 | ||
683 |
# Get tree (command "git ls-tree") |
|
684 |
my @entries = (); |
|
685 |
my $show_sizes = 0; |
|
686 |
open my $fh, '-|', $git->cmd($project), 'ls-tree', '-z', |
|
687 |
($show_sizes ? '-l' : ()), $tid |
|
688 |
or croak 'Open git-ls-tree failed'; |
|
689 |
local $/ = "\0"; |
|
690 |
@entries = map { chomp; $git->dec($_) } <$fh>; |
|
691 |
close $fh |
|
692 |
or croak 404, "Reading tree failed"; |
|
693 |
|
|
694 |
# Parse tree |
|
695 |
my @trees; |
|
696 |
for my $line (@entries) { |
|
697 |
my $tree = $git->parse_ls_tree_line($line, -z => 1, -l => $show_sizes); |
|
698 |
$tree->{mode_str} = $git->_mode_str($tree->{mode}); |
|
699 |
push @trees, $tree; |
|
700 |
} |
|
701 |
|
|
702 |
# References |
|
703 |
my $refs = $git->references($project); |
|
704 |
|
|
705 |
# Render |
|
706 |
$self->render( |
|
707 |
home => $home, |
|
708 |
home_ns => $home_ns, |
|
709 |
project => $project, |
|
710 |
project_ns => $project_ns, |
|
711 |
dir => $dir, |
|
712 |
id => $id, |
|
713 |
tid => $tid, |
|
714 |
commit => $commit, |
|
715 |
trees => \@trees, |
|
716 |
refs => $refs |
|
717 |
); |
|
718 |
} |
|
719 | ||
720 |
sub _parse_blobdiff_lines { |
|
721 |
my ($self, $lines_raw) = @_; |
|
722 |
|
|
723 |
# Git |
|
724 |
my $git = $self->app->git; |
|
725 |
|
|
726 |
# Parse |
|
727 |
my @lines; |
|
728 |
for my $line (@$lines_raw) { |
|
729 |
$line = $git->dec($line); |
|
730 |
chomp $line; |
|
731 |
my $class; |
|
732 |
|
|
733 |
if ($line =~ /^diff \-\-git /) { $class = 'diff header' } |
|
734 |
elsif ($line =~ /^index /) { $class = 'diff extended_header' } |
|
735 |
elsif ($line =~ /^\+/) { $class = 'diff to_file' } |
|
736 |
elsif ($line =~ /^\-/) { $class = 'diff from_file' } |
|
737 |
elsif ($line =~ /^\@\@/) { $class = 'diff chunk_header' } |
|
738 |
elsif ($line =~ /^Binary files/) { $class = 'diff binary_file' } |
|
739 |
else { $class = 'diff' } |
|
740 |
push @lines, {value => $line, class => $class}; |
|
741 |
} |
|
742 |
|
|
743 |
return \@lines; |
|
744 |
} |
|
745 | ||
746 |
sub _parse_id_path { |
|
747 |
my ($self, $project, $id_path) = @_; |
|
748 |
|
|
749 |
# Git |
|
750 |
my $git = $self->app->git; |
|
751 |
|
|
752 |
# Parse id and path |
|
753 |
my $refs = $git->references($project); |
|
754 |
my $id; |
|
755 |
my $path; |
|
756 |
for my $rs (values %$refs) { |
|
757 |
for my $ref (@$rs) { |
|
758 |
$ref =~ s#^heads/##; |
|
759 |
$ref =~ s#^tags/##; |
|
760 |
if ($id_path =~ s#^\Q$ref(/|$)##) { |
|
761 |
$id = $ref; |
|
762 |
$path = $id_path; |
|
763 |
last; |
|
764 |
} |
|
765 |
} |
|
766 |
} |
|
767 |
unless (defined $id) { |
|
768 |
if ($id_path =~ s#(^[^/]+)(/|$)##) { |
|
769 |
$id = $1; |
|
770 |
$path = $id_path; |
|
771 |
} |
|
772 |
} |
|
773 |
|
|
774 |
return ($id, $path); |
|
775 |
} |
|
776 | ||
777 |
sub _quote_command { |
|
778 |
my $self = shift; |
|
779 |
return join(' ', |
|
780 |
map { my $a = $_; $a =~ s/(['!])/'\\$1'/g; "'$a'" } @_ ); |
|
781 |
} |
|
782 | ||
783 |
1; |