Showing 8 changed files with 186 additions and 137 deletions
+35 -3
lib/Gitprep/Git.pm
... ...
@@ -8,6 +8,7 @@ use File::Basename qw/basename dirname/;
8 8
 use File::Copy 'move';
9 9
 use File::Find 'find';
10 10
 use File::Path qw/mkpath rmtree/;
11
+use POSIX 'floor';
11 12
 
12 13
 # Attributes
13 14
 has 'bin';
... ...
@@ -210,19 +211,27 @@ sub blob_diffs {
210 211
       or croak('Open self-diff-tree failed');
211 212
     my @lines = map { $self->_dec($_) } <$fh>;
212 213
     close $fh;
214
+    my ($lines, $diff_info) = $self->parse_blob_diff_lines(\@lines);
213 215
     my $blob_diff = {
214 216
       file => $file,
215 217
       from_file => $from_file,
216
-      lines => $self->parse_blob_diff_lines(\@lines)
218
+      lines => $lines,
219
+      add_line_count => $diff_info->{add_line_count},
220
+      delete_line_count => $diff_info->{delete_line_count}
217 221
     };
218 222
     
219
-    # Status
223
+    # Diff tree info
220 224
     for my $diff_tree (@$diff_trees) {
221 225
       if ($diff_tree->{to_file} eq $file) {
222 226
         $blob_diff->{status} = $diff_tree->{status};
227
+        $diff_tree->{add_line_count} = $diff_info->{add_line_count};
228
+        $diff_tree->{delete_line_count} = $diff_info->{delete_line_count};
229
+        $diff_tree->{add_block_count} = $diff_info->{add_block_count};
230
+        $diff_tree->{delete_block_count} = $diff_info->{delete_block_count};
223 231
         last;
224 232
       }
225 233
     }
234
+    
226 235
     push @$blob_diffs, $blob_diff;
227 236
   }
228 237
   
... ...
@@ -453,6 +462,8 @@ sub description {
453 462
 sub diff_tree {
454 463
   my ($self, $user, $project, $cid, $parent, $parents) = @_;
455 464
   
465
+  $parents = [] unless $parents;
466
+  
456 467
   # Root
457 468
   $parent = '--root' unless defined $parent;
458 469
 
... ...
@@ -1005,6 +1016,8 @@ sub parse_blob_diff_lines {
1005 1016
   my @lines;
1006 1017
   my $next_before_line_num;
1007 1018
   my $next_after_line_num;
1019
+  my $add_line_count = 0;
1020
+  my $delete_line_count = 0;
1008 1021
   for my $line (@$lines) {
1009 1022
     chomp $line;
1010 1023
     
... ...
@@ -1026,11 +1039,13 @@ sub parse_blob_diff_lines {
1026 1039
       $class = 'from_file';
1027 1040
       $before_line_num = $next_before_line_num++;
1028 1041
       $after_line_num = '';
1042
+      $delete_line_count++;
1029 1043
     }
1030 1044
     elsif ($line =~ /^\+/) {
1031 1045
       $class = 'to_file';
1032 1046
       $before_line_num = '';
1033 1047
       $after_line_num = $next_after_line_num++;
1048
+      $add_line_count++;
1034 1049
     }
1035 1050
     elsif ($line =~ /^Binary files/) { $class = 'binary_file' }
1036 1051
     elsif ($line =~ /^ /) {
... ...
@@ -1049,7 +1064,24 @@ sub parse_blob_diff_lines {
1049 1064
     push @lines, $line_data;
1050 1065
   }
1051 1066
   
1052
-  return \@lines;
1067
+  # Diff info
1068
+  my $diff_line_count = $add_line_count + $delete_line_count;
1069
+  my $add_block_count
1070
+    = $diff_line_count == 0
1071
+    ? 0
1072
+    : floor(($add_line_count * 5) / $diff_line_count);
1073
+  my $delete_block_count
1074
+    = $diff_line_count == 0
1075
+    ? 0
1076
+    : floor(($delete_line_count * 5) / $diff_line_count);
1077
+  
1078
+  my $diff_info = {
1079
+    add_line_count => $add_line_count,
1080
+    delete_line_count => $delete_line_count,
1081
+    add_block_count => $add_block_count,
1082
+    delete_block_count => $delete_block_count
1083
+  };
1084
+  return (\@lines, $diff_info);
1053 1085
 }
1054 1086
 
1055 1087
 sub get_commit {
+6 -82
templates/commit.html.ep
... ...
@@ -26,28 +26,6 @@
26 26
   $commit->{committer_date} = $git->timestamp($committer_date);
27 27
   $from_id = $commit->{parent} unless defined $from_id;
28 28
 
29
-  # Diff tree
30
-  my $diff_trees = $git->diff_tree(
31
-    $user,
32
-    $project,
33
-    $id,
34
-    $commit->{parent},
35
-    $commit->{parents}
36
-  );
37
-  my $diff_trees_h = {};
38
-  for my $diff_tree (@$diff_trees) {
39
-    my $file = $diff_tree->{file};
40
-    $diff_trees_h->{$file} = $diff_tree if defined $file;
41
-  }
42
-  
43
-  # Get blob diffs
44
-  my $blob_diffs = $git->blob_diffs($user, $project, $from_id, $id, $diff_trees) || [];
45
-  my $blob_diffs_h = {};
46
-  for my $blob_diff (@$blob_diffs) {
47
-    my $file = $blob_diff->{file};
48
-    $blob_diffs_h->{$file} = $blob_diff;
49
-  }
50
-  
51 29
   # Branches
52 30
   my $branch_refs = $git->references($user, $project, 'heads');
53 31
   my $branches = $branch_refs->{$commit->{id}} || [];
... ...
@@ -58,36 +36,16 @@
58 36
   
59 37
   # Global variable for included template
60 38
   stash(
61
-    from_id => $from_id,
62 39
     id => $id,
40
+    from_id => $from_id,
63 41
     rev => $id,
64
-    commit => $commit
42
+    commit => $commit,
43
+    parents => $commit->{parents}
65 44
   );
66 45
 %>
67 46
 
68 47
 % layout 'common';
69
-  
70
-  %= javascript begin
71
-    $(document).ready(function () {
72
-    
73
-      // Diff Stats Button
74
-      var diff_tree_show = false;
75
-      var original_diff_stats_btn_text = $('#diff-stats-btn').text();
76
-      
77
-      $('#diff-stats-btn').on('click', function () {
78
-        if (diff_tree_show) {
79
-          $(this).text(original_diff_stats_btn_text);
80
-          $('#diff_tree').css('display', 'none');
81
-        }
82
-        else {
83
-          $(this).text('Hide Diff Stats');
84
-          $('#diff_tree').css('display', 'block');
85
-        }
86
-        diff_tree_show = !diff_tree_show;
87
-      });
88
-    });
89
-  % end
90
-  
48
+
91 49
   %= include '/include/header', title => 'Commit diff';
92 50
 
93 51
   <div class="container">
... ...
@@ -173,41 +131,7 @@
173 131
         </div>
174 132
       </div>
175 133
     </div>
176
-
177
-    <div class="row" style="margin-bottom:10px">
178
-      <div class="span8" style="padding-top:5px">
179
-        Showing <b><%= @$diff_trees %> changed files</b>
180
-      </div>
181
-      <div class="text-right">
182
-        <button id="diff-stats-btn" class="btn">Show Diff Stats</button>
183
-      </div>
184
-    </div>
185
-    <div id="diff_tree" style="display:none">
186
-      <%= include '/include/diff_tree', id => $commit->{id}, from_id => $commit->{parent},
187
-        diff_trees => $diff_trees, parents => $commit->{parents}, project_ns => $project %>
188
-    </div>
189
-    % my $num = 0;
190
-    % for my $file (sort keys %$diff_trees_h) {
191
-      <div id="diff-<%= $num %>">
192
-        % my $blob_diff = $blob_diffs_h->{$file};
193
-        % if ($blob_diff) {
194
-          % my $lines = $blob_diff->{lines};
195
-          % my $file = $blob_diff->{file};
196
-          % my $from_file = $blob_diff->{from_file};
197
-          % $from_file = $file unless defined $from_file;
198
-          % my $status = $blob_diff->{status};
199
-          %= include '/include/blob_diff_body', file => $file, from_file => $from_file, status => $status, lines => $blob_diff->{lines}, project_ns => $project;
200
-        % } else {
201
-          <div class="border-gray bk-gray-light" style="border-bottom:none;padding:10px">
202
-            <%= $file %>
203
-          </div>
204
-          <div class="border-gray" style="padding:10px;margin-bottom:30px">
205
-            No changes. Empty file is added.
206
-          </div>
207
-        % }
208
-      </div>
209
-      % $num++;
210
-    % }
211
-  </div>
134
+  
135
+  %= include '/include/commit_body';
212 136
   
213 137
   %= include '/include/footer';
+5 -42
templates/compare.html.ep
... ...
@@ -37,30 +37,15 @@
37 37
     return;
38 38
   }
39 39
   
40
-  # Diff tree
41
-  my $diff_trees = $git->diff_tree(
42
-    $user,
43
-    $project,
44
-    $end_commit->{id},
45
-    $start_commit->{id},
46
-    []
47
-  );
48
-  
49
-  # Get blob diffs (command "git diff-tree")
50
-  my $blob_diffs = $git->blob_diffs(
51
-    $user,
52
-    $project,
53
-    $start_commit->{id},
54
-    $end_commit->{id},
55
-    $diff_trees
56
-  );
57
-  
58 40
   # Branches
59 41
   my $branches = $git->branches($user, $project);
60 42
   @$branches = sort { $a->{commit}{age} <=> $b->{commit}{age} } @$branches;
61 43
   
62 44
   # Global variables
63
-  stash(user => $user, project => $project);
45
+  stash(
46
+    id => $end_commit->{id},
47
+    from_id => $start_commit->{id},
48
+  );
64 49
 %>
65 50
 
66 51
 % layout 'common';
... ...
@@ -239,29 +224,7 @@
239 224
         </div>
240 225
         
241 226
         <div class="tab-pane" id="file-changed">
242
-          <div style="margin-bottom:5px">
243
-            Showing <b><%= @$diff_trees %> changed files</b>
244
-          </div>
245
-          <div>
246
-            <%= include '/include/diff_tree', id => $end_commit->{id}, from_id => $start_commit->{id},
247
-              diff_trees => $diff_trees, parents => [], project_ns => $project %>
248
-          </div>
249
-          <div>
250
-            <div>
251
-              % my $num = 0;
252
-              % for (my $i = 0; $i < @$blob_diffs; $i++) {
253
-                % my $blob_diff = $blob_diffs->[$i];
254
-                <div id="diff-<%= $i %>" >
255
-                  % my $lines = $blob_diff->{lines};
256
-                  % my $file = $blob_diff->{file};
257
-                  % my $from_file = $blob_diff->{from_file};
258
-                  % $from_file = $file unless defined $from_file;
259
-                  % my $status = $blob_diff->{status};
260
-                  %= include '/include/blob_diff_body', file => $file, from_file => $from_file, status => $status, lines => $blob_diff->{lines}, project_ns => $project, from_id => $start_commit->{id}, id => $end_commit->{id};
261
-                </div>
262
-              % }
263
-            </div>
264
-          </div>
227
+          %= include '/include/commit_body';
265 228
         </div>
266 229
       </div>
267 230
     % } else {
+5 -1
templates/include/blob_diff_body.html.ep
... ...
@@ -1,11 +1,15 @@
1 1
 <%
2 2
   my $status = stash('status') || '';
3
+  my $diff_tree = stash('diff_tree');
3 4
 %>
4 5
 
5 6
 <div style="margin-bottom:20px;">
6 7
   <div class="border-gray bk-gray-light" style="padding:5px">
7 8
     <div class="row">
8
-      <div class="span8" style="padding-top:6px">
9
+      <div class="span8" style="padding-top:3px">
10
+        <div class="radius-top radius-bottom" style="padding:1px 3px;margin-right:5px;border:1px solid #ccc;display:inline-block;background:#f7f7f7">
11
+          %= include '/include/diff_status_bar', diff_tree => $diff_tree;
12
+        </div>
9 13
         <%= $file %>
10 14
       </div>
11 15
       <div class="text-right">
+88
templates/include/commit_body.html.ep
... ...
@@ -0,0 +1,88 @@
1
+<%
2
+  # Parameters
3
+  my $id = stash('id');
4
+  my $from_id = stash('from_id');
5
+  my $parents = stash('parents');
6
+  
7
+  # Git
8
+  my $git = app->git;
9
+  
10
+  # Diff tree
11
+  my $diff_trees = $git->diff_tree(
12
+    $user,
13
+    $project,
14
+    $id,
15
+    $from_id,
16
+    $parents
17
+  );
18
+  my $diff_trees_h = {};
19
+  for my $diff_tree (@$diff_trees) {
20
+    my $file = $diff_tree->{file};
21
+    $diff_trees_h->{$file} = $diff_tree if defined $file;
22
+  }
23
+  
24
+  # Get blob diffs
25
+  my $blob_diffs = $git->blob_diffs($user, $project, $from_id, $id, $diff_trees) || [];
26
+  my $blob_diffs_h = {};
27
+  for my $blob_diff (@$blob_diffs) {
28
+    my $file = $blob_diff->{file};
29
+    $blob_diffs_h->{$file} = $blob_diff;
30
+  }
31
+%>
32
+
33
+%= javascript begin
34
+  $(document).ready(function () {
35
+  
36
+    // Diff Stats Button
37
+    var diff_tree_show = false;
38
+    var original_diff_stats_btn_text = $('#diff-stats-btn').text();
39
+    
40
+    $('#diff-stats-btn').on('click', function () {
41
+      if (diff_tree_show) {
42
+        $(this).text(original_diff_stats_btn_text);
43
+        $('#diff_tree').css('display', 'none');
44
+      }
45
+      else {
46
+        $(this).text('Hide Diff Stats');
47
+        $('#diff_tree').css('display', 'block');
48
+      }
49
+      diff_tree_show = !diff_tree_show;
50
+    });
51
+  });
52
+% end
53
+
54
+<div class="row" style="margin-bottom:10px">
55
+  <div class="span8" style="padding-top:5px">
56
+    Showing <b><%= @$diff_trees %> changed files</b>
57
+  </div>
58
+  <div class="text-right">
59
+    <button id="diff-stats-btn" class="btn">Show Diff Stats</button>
60
+  </div>
61
+</div>
62
+<div id="diff_tree" style="display:none">
63
+  <%= include '/include/diff_tree', id => $id, from_id => $from_id,
64
+    diff_trees => $diff_trees, parents => $parents %>
65
+</div>
66
+% my $num = 0;
67
+% for my $file (sort keys %$diff_trees_h) {
68
+  <div id="diff-<%= $num %>">
69
+    % my $blob_diff = $blob_diffs_h->{$file};
70
+    % if ($blob_diff) {
71
+      % my $lines = $blob_diff->{lines};
72
+      % my $file = $blob_diff->{file};
73
+      % my $from_file = $blob_diff->{from_file};
74
+      % $from_file = $file unless defined $from_file;
75
+      % my $status = $blob_diff->{status};
76
+      %= include '/include/blob_diff_body', diff_tree => $diff_trees_h->{$file}, file => $file, from_file => $from_file, status => $status, lines => $blob_diff->{lines};
77
+    % } else {
78
+      <div class="border-gray bk-gray-light" style="border-bottom:none;padding:10px">
79
+        <%= $file %>
80
+      </div>
81
+      <div class="border-gray" style="padding:10px;margin-bottom:30px">
82
+        No changes. Empty file is added.
83
+      </div>
84
+    % }
85
+  </div>
86
+  % $num++;
87
+% }
88
+</div>
+27
templates/include/diff_status_bar.html.ep
... ...
@@ -0,0 +1,27 @@
1
+<%
2
+  my $diff_tree = stash('diff_tree');
3
+  my $fragment = stash('fragment');
4
+  my $add_line_count = $diff_tree->{add_line_count} || 0;
5
+  my $delete_line_count = $diff_tree->{delete_line_count} || 0;
6
+  my $diff_line_count = $add_line_count + $delete_line_count;
7
+  my $diff_count_text = "$add_line_count additions";
8
+  $diff_count_text .= " & $delete_line_count deletions" if $delete_line_count > 0;
9
+  my $tag = $fragment ? 'a' : 'span';
10
+  my $add_block_count = $diff_tree->{add_block_count} || 0;
11
+  my $delete_block_count = $diff_tree->{delete_block_count} || 0;
12
+%>
13
+
14
+
15
+<<%= $tag %> title="<%= $diff_count_text %>" style="text-decoration:none;color:#666" href="#<%= $fragment %>"><%= $diff_line_count %></<%= $tag %>>
16
+
17
+<<%= $tag %> title="<%= $diff_count_text %>" style="text-decoration:none;display:inline-block;overflow:none;" href="#<%= $fragment %>">
18
+  % for (my $i = 0; $i < $add_block_count; $i++) {
19
+    <div style="display:inline-block;background:#6cc644;width:8px;height:9px;float:left;margin:1px"></div>
20
+  % }
21
+  % for (my $i = 0; $i < $delete_block_count; $i++) {
22
+    <div style="display:inline-block;background:#bd2c00;width:8px;height:9px;float:left;margin:1px"></div>
23
+  % }
24
+  % for (my $i = 0; $i < 5 - $add_block_count - $delete_block_count; $i++) {
25
+    <div style="display:inline-block;background:#eee;width:8px;height:9px;float:left;margin:1px"></div>
26
+  % }
27
+</<%= $tag %>>
+14 -7
templates/include/diff_tree.html.ep
... ...
@@ -1,3 +1,7 @@
1
+<%
2
+  my $parents = stash('parents') || [];
3
+%>
4
+
1 5
 %= stylesheet begin
2 6
   .file-add {
3 7
     color:#32CD32;
... ...
@@ -28,8 +32,8 @@
28 32
   }
29 33
 
30 34
   .file-modified {
31
-    color:#A9A9A9;
32
-    border:2px #A9A9A9 solid;
35
+    color:#DAA520;
36
+    border:2px #DAA520 solid;
33 37
     margin-left:3px;
34 38
     font-weight:bold;
35 39
     line-height:0;
... ...
@@ -38,11 +42,11 @@
38 42
     vertical-align:middle;
39 43
     width:9px;
40 44
     height:9px;
41
-    font-size:13px;
45
+    font-size:11px;
42 46
   }
43 47
 % end
44 48
   
45
-<table style="margin-bottom:10px">
49
+<table style="margin-bottom:10px;width:100%">
46 50
   
47 51
   % my $has_header = @$diff_trees && @$parents > 1 && stash('action') eq 'commitdiff';
48 52
   % if ($has_header) {
... ...
@@ -64,7 +68,7 @@
64 68
   % my $toggle = 0;
65 69
   % my $num = 0;
66 70
   % for my $diff_tree (@$diff_trees) {
67
-    <tr>
71
+    <tr style="<%= $num + 1 ne @$diff_trees ? 'border-bottom:1px #ddd solid' : '' %>">
68 72
       % if (exists $diff_tree->{'nparents'}) {
69 73
         % my $file = $diff_tree->{to_file};
70 74
         
... ...
@@ -132,7 +136,7 @@
132 136
         % my $from_mode = $diff_tree->{from_mode};
133 137
         % my $from_mode_str = $diff_tree->{from_mode_str};
134 138
         % my $from_mode_oct = $diff_tree->{from_mode_oct};
135
-        <td>
139
+        <td style="padding:7px 0; width:12px">
136 140
           % if ($status eq 'A') {
137 141
             <div class="file-add">+</div>
138 142
           % } elsif ($status eq 'D') {
... ...
@@ -175,7 +179,10 @@
175 179
           % }
176 180
         </td>
177 181
         <td>
178
-          <a style="margin-left:5px" href="<%= url_for->fragment("diff-$num") %>"><%= $file %></a>
182
+          <a style="margin-left:5px" href="#<%= "diff-$num" %>"><%= $file %></a>
183
+        </td>
184
+        <td style="text-align:right">
185
+          %= include '/include/diff_status_bar', diff_tree => $diff_tree, fragment => "diff-$num";
179 186
         </td>
180 187
       % }
181 188
     </tr>
+6 -2
xt/basic.t
... ...
@@ -77,6 +77,7 @@ note 'Project page';
77 77
 
78 78
 note 'Commit page';
79 79
 {
80
+  note 'first commit';
80 81
   {
81 82
     # Page access
82 83
     $t->get_ok("/$user/$project/commit/4b0e81c462088b16fefbe545e00b993fd7e6f884");
... ...
@@ -105,17 +106,20 @@ note 'Commit page';
105 106
     # Empty file is added
106 107
     $t->content_like(qr/No changes/);
107 108
   }
109
+  
110
+  note 'Branch name';
108 111
   {
109 112
     # Page access (branch name)
110 113
     $t->get_ok("/$user/$project/commit/b1");
111 114
     $t->content_like(qr/\+bbb/);
112
-  }
113
-  {
115
+
114 116
     # Page access (branch name long)
115 117
     $t->get_ok("/$user/$project/commit/refs/heads/b1");
116 118
     $t->content_like(qr/\+bbb/);
117 119
     $t->content_like(qr#refs/heads/b1#);
118 120
   }
121
+  
122
+  
119 123
 }
120 124
 
121 125
 note 'Commits page';