... | ... |
@@ -62,7 +62,7 @@ sub startup { |
62 | 62 |
$r->get('/:user/:project')->to('#project'); |
63 | 63 |
|
64 | 64 |
# Commit |
65 |
- $r->get('/:user/:project/commit/:id')->to('#commit'); |
|
65 |
+ $r->get('/:user/:project/commit/:diff')->to('#commitdiff'); |
|
66 | 66 |
|
67 | 67 |
# Commits |
68 | 68 |
$r->get('/:user/:project/commits/:rev', {id => 'HEAD'})->to('#commits'); |
... | ... |
@@ -653,6 +653,29 @@ sub latest_commit_log { |
653 | 653 |
return $commit_log; |
654 | 654 |
} |
655 | 655 |
|
656 |
+sub parse_blobdiff_lines { |
|
657 |
+ my ($self, $lines_raw) = @_; |
|
658 |
+ |
|
659 |
+ # Parse |
|
660 |
+ my @lines; |
|
661 |
+ for my $line (@$lines_raw) { |
|
662 |
+ $line = $self->dec($line); |
|
663 |
+ chomp $line; |
|
664 |
+ my $class; |
|
665 |
+ |
|
666 |
+ if ($line =~ /^diff \-\-git /) { $class = 'diff header' } |
|
667 |
+ elsif ($line =~ /^index /) { $class = 'diff extended_header' } |
|
668 |
+ elsif ($line =~ /^\+/) { $class = 'diff to_file' } |
|
669 |
+ elsif ($line =~ /^\-/) { $class = 'diff from_file' } |
|
670 |
+ elsif ($line =~ /^\@\@/) { $class = 'diff chunk_header' } |
|
671 |
+ elsif ($line =~ /^Binary files/) { $class = 'diff binary_file' } |
|
672 |
+ else { $class = 'diff' } |
|
673 |
+ push @lines, {value => $line, class => $class}; |
|
674 |
+ } |
|
675 |
+ |
|
676 |
+ return \@lines; |
|
677 |
+} |
|
678 |
+ |
|
656 | 679 |
sub parse_commit { |
657 | 680 |
my ($self, $project, $id) = @_; |
658 | 681 |
|
... | ... |
@@ -70,126 +70,6 @@ sub blobdiff { |
70 | 70 |
} |
71 | 71 |
} |
72 | 72 |
|
73 |
-sub commitdiff { |
|
74 |
- my $self = shift; |
|
75 |
- |
|
76 |
- # Paramters |
|
77 |
- my $project_ns = $self->param('project'); |
|
78 |
- my $project = "/$project_ns"; |
|
79 |
- my $home_ns = dirname $project_ns; |
|
80 |
- my $home = "/$home_ns"; |
|
81 |
- my $diff = $self->param('diff'); |
|
82 |
- my ($from_id, $id) = $diff =~ /(.+)\.\.(.+)/; |
|
83 |
- $id = $diff unless defined $id; |
|
84 |
- |
|
85 |
- # Git |
|
86 |
- my $git = $self->app->git; |
|
87 |
- |
|
88 |
- # Commit |
|
89 |
- my $commit = $git->parse_commit($project, $id) |
|
90 |
- or croak 'Unknown commit object'; |
|
91 |
- my $author_date |
|
92 |
- = $git->parse_date($commit->{author_epoch}, $commit->{author_tz}); |
|
93 |
- my $committer_date |
|
94 |
- = $git->parse_date($commit->{committer_epoch}, $commit->{committer_tz}); |
|
95 |
- $commit->{author_date} = $git->timestamp($author_date); |
|
96 |
- $commit->{committer_date} = $git->timestamp($committer_date); |
|
97 |
- $from_id = $commit->{parent} unless defined $from_id; |
|
98 |
- |
|
99 |
- # Plain text |
|
100 |
- if ($self->param('plain')) { |
|
101 |
- # Get blob diffs (command "git diff-tree") |
|
102 |
- my @cmd = ($git->cmd($project), 'diff-tree', '-r', '-M', |
|
103 |
- '-p', $from_id, $id, '--'); |
|
104 |
- open my $fh, '-|', @cmd |
|
105 |
- or croak 'Open git-diff-tree failed'; |
|
106 |
- |
|
107 |
- # Content |
|
108 |
- my $content = do { local $/; <$fh> }; |
|
109 |
- my $content_disposition .= "inline; filename=$id"; |
|
110 |
- |
|
111 |
- # Render |
|
112 |
- $self->res->headers->content_disposition($content_disposition); |
|
113 |
- $self->res->headers->content_type("text/plain;charset=" . $git->encoding); |
|
114 |
- $self->render_data($content); |
|
115 |
- } |
|
116 |
- |
|
117 |
- # HTML |
|
118 |
- else { |
|
119 |
- |
|
120 |
- # Diff tree |
|
121 |
- my $difftrees = $git->difftree($project, |
|
122 |
- $id, $commit->{parent}, $commit->{parents}); |
|
123 |
- |
|
124 |
- # Get blob diffs (command "git diff-tree") |
|
125 |
- my @cmd = ($git->cmd($project), 'diff-tree', '-r', '-M', |
|
126 |
- '--no-commit-id', '--patch-with-raw', $from_id, $id, '--'); |
|
127 |
- open my $fh, '-|', @cmd |
|
128 |
- or croak 'Open git-diff-tree failed'; |
|
129 |
- |
|
130 |
- # Parse output |
|
131 |
- my @blobdiffs; |
|
132 |
- while (my $line = $git->dec(scalar <$fh>)) { |
|
133 |
- |
|
134 |
- # Parse line |
|
135 |
- chomp $line; |
|
136 |
- my $diffinfo = $git->parse_difftree_raw_line($line); |
|
137 |
- my $from_file = $diffinfo->{from_file}; |
|
138 |
- my $file = $diffinfo->{to_file}; |
|
139 |
- |
|
140 |
- # Get blobdiff (command "git diff-tree") |
|
141 |
- my @cmd = ($git->cmd($project), 'diff-tree', '-r', '-M', '-p', |
|
142 |
- $from_id, $id, '--', (defined $from_file ? $from_file : ()), $file); |
|
143 |
- open my $fh_blobdiff, '-|', @cmd |
|
144 |
- or croak 'Open git-diff-tree failed'; |
|
145 |
- my @lines = map { $git->dec($_) } <$fh>; |
|
146 |
- close $fh_blobdiff; |
|
147 |
- my $blobdiff = { |
|
148 |
- file => $file, |
|
149 |
- from_file => $from_file, |
|
150 |
- lines => $self->_parse_blobdiff_lines(\@lines) |
|
151 |
- }; |
|
152 |
- |
|
153 |
- # Status |
|
154 |
- for my $difftree (@$difftrees) { |
|
155 |
- if ($difftree->{to_file} eq $file) { |
|
156 |
- $blobdiff->{status} = $difftree->{status}; |
|
157 |
- last; |
|
158 |
- } |
|
159 |
- } |
|
160 |
- |
|
161 |
- push @blobdiffs, $blobdiff; |
|
162 |
- } |
|
163 |
- |
|
164 |
- # References |
|
165 |
- my $refs = $git->references($project); |
|
166 |
- |
|
167 |
- # Render |
|
168 |
- $self->render( |
|
169 |
- 'commitdiff', |
|
170 |
- home => $home, |
|
171 |
- home_ns => $home_ns, |
|
172 |
- project => $project, |
|
173 |
- project_ns => $project_ns, |
|
174 |
- from_id => $from_id, |
|
175 |
- id => $id, |
|
176 |
- commit => $commit, |
|
177 |
- difftrees => $difftrees, |
|
178 |
- blobdiffs => \@blobdiffs, |
|
179 |
- refs => $refs |
|
180 |
- ); |
|
181 |
- } |
|
182 |
-} |
|
183 |
- |
|
184 |
-sub _root_ns { |
|
185 |
- my $self = shift; |
|
186 |
- |
|
187 |
- my $root = $self->root; |
|
188 |
- $root =~ s/^\///; |
|
189 |
- |
|
190 |
- return $root; |
|
191 |
-} |
|
192 |
- |
|
193 | 73 |
sub snapshot { |
194 | 74 |
my $self = shift; |
195 | 75 |
|
... | ... |
@@ -267,63 +147,6 @@ sub tag { |
267 | 147 |
); |
268 | 148 |
} |
269 | 149 |
|
270 |
-sub _parse_blobdiff_lines { |
|
271 |
- my ($self, $lines_raw) = @_; |
|
272 |
- |
|
273 |
- # Git |
|
274 |
- my $git = $self->app->git; |
|
275 |
- |
|
276 |
- # Parse |
|
277 |
- my @lines; |
|
278 |
- for my $line (@$lines_raw) { |
|
279 |
- $line = $git->dec($line); |
|
280 |
- chomp $line; |
|
281 |
- my $class; |
|
282 |
- |
|
283 |
- if ($line =~ /^diff \-\-git /) { $class = 'diff header' } |
|
284 |
- elsif ($line =~ /^index /) { $class = 'diff extended_header' } |
|
285 |
- elsif ($line =~ /^\+/) { $class = 'diff to_file' } |
|
286 |
- elsif ($line =~ /^\-/) { $class = 'diff from_file' } |
|
287 |
- elsif ($line =~ /^\@\@/) { $class = 'diff chunk_header' } |
|
288 |
- elsif ($line =~ /^Binary files/) { $class = 'diff binary_file' } |
|
289 |
- else { $class = 'diff' } |
|
290 |
- push @lines, {value => $line, class => $class}; |
|
291 |
- } |
|
292 |
- |
|
293 |
- return \@lines; |
|
294 |
-} |
|
295 |
- |
|
296 |
-sub _parse_id_path { |
|
297 |
- my ($self, $project, $id_path) = @_; |
|
298 |
- |
|
299 |
- # Git |
|
300 |
- my $git = $self->app->git; |
|
301 |
- |
|
302 |
- # Parse id and path |
|
303 |
- my $refs = $git->references($project); |
|
304 |
- my $id; |
|
305 |
- my $path; |
|
306 |
- for my $rs (values %$refs) { |
|
307 |
- for my $ref (@$rs) { |
|
308 |
- $ref =~ s#^heads/##; |
|
309 |
- $ref =~ s#^tags/##; |
|
310 |
- if ($id_path =~ s#^\Q$ref(/|$)##) { |
|
311 |
- $id = $ref; |
|
312 |
- $path = $id_path; |
|
313 |
- last; |
|
314 |
- } |
|
315 |
- } |
|
316 |
- } |
|
317 |
- unless (defined $id) { |
|
318 |
- if ($id_path =~ s#(^[^/]+)(/|$)##) { |
|
319 |
- $id = $1; |
|
320 |
- $path = $id_path; |
|
321 |
- } |
|
322 |
- } |
|
323 |
- |
|
324 |
- return ($id, $path); |
|
325 |
-} |
|
326 |
- |
|
327 | 150 |
sub _quote_command { |
328 | 151 |
my $self = shift; |
329 | 152 |
return join(' ', |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
<table class="<%= @$parents > 1 ? 'combined' : 'diff_tree' %>""> |
2 |
- |
|
2 |
+ |
|
3 | 3 |
% my $has_header = @$difftrees && @$parents > 1 && stash('action') eq 'commitdiff'; |
4 | 4 |
% if ($has_header) { |
5 | 5 |
<thead> |
... | ... |
@@ -2,12 +2,10 @@ |
2 | 2 |
# API |
3 | 3 |
my $api = Gitprep::API->new($self); |
4 | 4 |
|
5 |
- # Parameter |
|
5 |
+ # Parameters |
|
6 | 6 |
my $user = param('user'); |
7 | 7 |
my $project = param('project'); |
8 | 8 |
my $root_ns = $api->root_ns(config->{root}); |
9 |
- |
|
10 |
- # Parameters |
|
11 | 9 |
my $rep_ns = "$root_ns/$user/$project.git"; |
12 | 10 |
my $rep = "/$rep_ns"; |
13 | 11 |
my $object = param('object'); |
... | ... |
@@ -1,19 +1,128 @@ |
1 |
+<% |
|
2 |
+ use Gitprep::API; |
|
3 |
+ |
|
4 |
+ # API |
|
5 |
+ my $api = Gitprep::API->new($self); |
|
6 |
+ |
|
7 |
+ # Paramters |
|
8 |
+ my $project = param('project'); |
|
9 |
+ my $root_ns = $api->root_ns(config->{root}); |
|
10 |
+ my $rep_ns = "$root_ns/$user/$project.git"; |
|
11 |
+ my $rep = "/$rep_ns"; |
|
12 |
+ my $home_ns = $api->dirname($project); |
|
13 |
+ my $home = "/$home_ns"; |
|
14 |
+ my $diff = param('diff'); |
|
15 |
+ my ($from_id, $id) = $diff =~ /(.+)\.\.(.+)/; |
|
16 |
+ $id = $diff unless defined $id; |
|
17 |
+ |
|
18 |
+ # Git |
|
19 |
+ my $git = app->git; |
|
20 |
+ |
|
21 |
+ # Commit |
|
22 |
+ my $commit = $git->parse_commit($rep, $id) |
|
23 |
+ or $api->croak('Unknown commit object'); |
|
24 |
+ my $author_date |
|
25 |
+ = $git->parse_date($commit->{author_epoch}, $commit->{author_tz}); |
|
26 |
+ my $committer_date |
|
27 |
+ = $git->parse_date($commit->{committer_epoch}, $commit->{committer_tz}); |
|
28 |
+ $commit->{author_date} = $git->timestamp($author_date); |
|
29 |
+ $commit->{committer_date} = $git->timestamp($committer_date); |
|
30 |
+ $from_id = $commit->{parent} unless defined $from_id; |
|
31 |
+ |
|
32 |
+ my $difftrees; |
|
33 |
+ my $blobdiffs; |
|
34 |
+ |
|
35 |
+ # Plain text |
|
36 |
+ if ($self->param('plain')) { |
|
37 |
+ # Get blob diffs (command "git diff-tree") |
|
38 |
+ my @cmd = ($git->cmd($rep), 'diff-tree', '-r', '-M', |
|
39 |
+ '-p', $from_id, $id, '--'); |
|
40 |
+ open my $fh, '-|', @cmd |
|
41 |
+ or $api->croak('Open git-diff-tree failed'); |
|
42 |
+ |
|
43 |
+ # Content |
|
44 |
+ my $content = do { local $/; <$fh> }; |
|
45 |
+ my $content_disposition .= "inline; filename=$id"; |
|
46 |
+ |
|
47 |
+ # Render |
|
48 |
+ $self->res->headers->content_disposition($content_disposition); |
|
49 |
+ $self->res->headers->content_type("text/plain;charset=" . $git->encoding); |
|
50 |
+ $self->render_data($content); |
|
51 |
+ } |
|
52 |
+ |
|
53 |
+ # HTML |
|
54 |
+ else { |
|
55 |
+ |
|
56 |
+ # Diff tree |
|
57 |
+ $difftrees = $git->difftree($rep, |
|
58 |
+ $id, $commit->{parent}, $commit->{parents}); |
|
59 |
+ |
|
60 |
+ # Get blob diffs (command "git diff-tree") |
|
61 |
+ my @cmd = ($git->cmd($rep), 'diff-tree', '-r', '-M', |
|
62 |
+ '--no-commit-id', '--patch-with-raw', $from_id, $id, '--'); |
|
63 |
+ open my $fh, '-|', @cmd |
|
64 |
+ or $api->croak('Open git-diff-tree failed'); |
|
65 |
+ |
|
66 |
+ # Parse output |
|
67 |
+ while (my $line = $git->dec(scalar <$fh>)) { |
|
68 |
+ |
|
69 |
+ # Parse line |
|
70 |
+ chomp $line; |
|
71 |
+ my $diffinfo = $git->parse_difftree_raw_line($line); |
|
72 |
+ my $from_file = $diffinfo->{from_file}; |
|
73 |
+ my $file = $diffinfo->{to_file}; |
|
74 |
+ |
|
75 |
+ # Get blobdiff (command "git diff-tree") |
|
76 |
+ my @cmd = ($git->cmd($rep), 'diff-tree', '-r', '-M', '-p', |
|
77 |
+ $from_id, $id, '--', (defined $from_file ? $from_file : ()), $file); |
|
78 |
+ open my $fh_blobdiff, '-|', @cmd |
|
79 |
+ or $api->croak('Open git-diff-tree failed'); |
|
80 |
+ my @lines = map { $git->dec($_) } <$fh>; |
|
81 |
+ close $fh_blobdiff; |
|
82 |
+ my $blobdiff = { |
|
83 |
+ file => $file, |
|
84 |
+ from_file => $from_file, |
|
85 |
+ lines => $git->parse_blobdiff_lines(\@lines) |
|
86 |
+ }; |
|
87 |
+ |
|
88 |
+ # Status |
|
89 |
+ for my $difftree (@$difftrees) { |
|
90 |
+ if ($difftree->{to_file} eq $file) { |
|
91 |
+ $blobdiff->{status} = $difftree->{status}; |
|
92 |
+ last; |
|
93 |
+ } |
|
94 |
+ } |
|
95 |
+ |
|
96 |
+ push @$blobdiffs, $blobdiff; |
|
97 |
+ } |
|
98 |
+ |
|
99 |
+ # Render |
|
100 |
+ stash( |
|
101 |
+ home => $home, |
|
102 |
+ home_ns => $home_ns, |
|
103 |
+ project => $project, |
|
104 |
+ project => $project, |
|
105 |
+ from_id => $from_id, |
|
106 |
+ id => $id, |
|
107 |
+ commit => $commit, |
|
108 |
+ ); |
|
109 |
+ } |
|
110 |
+%> |
|
111 |
+ |
|
1 | 112 |
% layout 'common'; |
113 |
+ %= include '/css/common'; |
|
2 | 114 |
%= include '/include/header', title => 'Commit diff', project => $project; |
3 |
- %= include '/include/current_directory', home_ns => $home_ns, home => $home; |
|
4 |
- %= include '/include/page_navi', current => 'commitdiff', project_ns => $project_ns; |
|
5 | 115 |
<div class="page_nav"> |
6 |
- <a href="<%= url_for('commitdiff_plain', project => $project_ns, diff => $commit->{id}) %>"> |
|
116 |
+ <a href="<%= url_for('commitdiff_plain', project => $project, diff => $commit->{id}) %>"> |
|
7 | 117 |
Raw |
8 | 118 |
</a> |
9 | 119 |
</div> |
10 | 120 |
<div class="header"> |
11 |
- <a class="title" href="<%= url_for('commit', project => $project_ns) %>"> |
|
121 |
+ <a class="title" href="<%= url_for('commit', project => $project) %>"> |
|
12 | 122 |
<%= $commit->{title} %> |
13 | 123 |
</a> |
14 | 124 |
</div> |
15 | 125 |
<div class="title_text"> |
16 |
- %= include 'include/refs', project_ns => $project_ns, commit => $commit, refs => $refs; |
|
17 | 126 |
<table class="object_header"> |
18 | 127 |
<tr><td>Author</td><td><%= $commit->{author} %></td><td rowspan="2"></td></tr> |
19 | 128 |
<tr><td></td><td><%= $commit->{author_date} %></td></tr> |
... | ... |
@@ -25,7 +134,7 @@ |
25 | 134 |
<div class="list_head"></div> |
26 | 135 |
|
27 | 136 |
<%= include '/include/difftree', id => $commit->{id}, from_id => $commit->{parent}, |
28 |
- difftrees => $difftrees, parents => $commit->{parents} %> |
|
137 |
+ difftrees => $difftrees, parents => $commit->{parents}, project_ns => $project %> |
|
29 | 138 |
|
30 | 139 |
<div class="patchset"> |
31 | 140 |
% for (my $i = 0; $i < @$blobdiffs; $i++) { |
... | ... |
@@ -36,7 +145,7 @@ |
36 | 145 |
% my $from_file = $blobdiff->{from_file}; |
37 | 146 |
% $from_file = $file unless defined $from_file; |
38 | 147 |
% my $status = $blobdiff->{status}; |
39 |
- %= include '/include/blobdiff_body', file => $file, from_file => $from_file, status => $status, lines => $blobdiff->{lines}; |
|
148 |
+ %= include '/include/blobdiff_body', file => $file, from_file => $from_file, status => $status, lines => $blobdiff->{lines}, project_ns => $project; |
|
40 | 149 |
</div> |
41 | 150 |
% } |
42 | 151 |
</div> |