Showing 10 changed files with 272 additions and 105 deletions
+9 -13
lib/Gitprep.pm
... ...
@@ -180,36 +180,32 @@ sub startup {
180 180
       $r->get('/')->name('project');
181 181
       
182 182
       # Commit
183
-      $r->get('/commit/#diff')->name('commit');
183
+      $r->get('/commit/*diff')->name('commit');
184 184
       
185 185
       # Commits
186
-      $r->get('/commits/#rev', {id => 'HEAD'})->name('commits');
187
-      $r->get('/commits/#rev/(*blob)')->name('commits');
186
+      $r->get('/commits/*rev_file', {file => undef})->name('commits');
188 187
       
189 188
       # Branches
190
-      $r->any('/branches/:base_branch', {base_branch => undef})->name('branches');
189
+      $r->any('/branches/*base_branch', {base_branch => undef})->name('branches');
191 190
 
192 191
       # Tags
193 192
       $r->get('/tags')->name('tags');
194 193
 
195 194
       # Tree
196
-      $r->get('/tree/:rev/(*dir)', {dir => undef})->name('tree');
195
+      $r->get('/tree/*rev_dir', {dir => undef})->name('tree');
197 196
       
198 197
       # Blob
199
-      $r->get('/blob/:rev/(*file)', {file => undef})->name('blob');
200
-      
201
-      # Blob diff
202
-      $r->get('/blobdiff/(#diff)/(*file)')->name('blobdiff');
198
+      $r->get('/blob/*rev_file', {file => undef})->name('blob');
203 199
       
204 200
       # Raw
205
-      $r->get('/raw/:rev/(*file)', {file => undef})->name('raw');
201
+      $r->get('/raw/*rev_file', {file => undef})->name('raw');
206 202
       
207 203
       # Archive
208
-      $r->get('/archive/(:rev).(tar.gz')->name('archive')->to(archive_type => 'tar');
209
-      $r->get('/archive/(:rev).zip')->name('archive')->to(archive_type => 'zip');
204
+      $r->get('/archive/(*rev).tar.gz')->name('archive')->to(archive_type => 'tar');
205
+      $r->get('/archive/(*rev).zip')->name('archive')->to(archive_type => 'zip');
210 206
       
211 207
       # Compare
212
-      $r->get('/compare/(#rev1)...(#rev2)')->name('compare');
208
+      $r->get('/compare/(*rev1)...(*rev2)')->name('compare');
213 209
       
214 210
       # Settings
215 211
       $r->any('/settings')->name('project-settings');
+51 -2
lib/Gitprep/Git.pm
... ...
@@ -35,6 +35,54 @@ sub _dec {
35 35
   return $@ ? $str : $new_str;
36 36
 }
37 37
 
38
+sub parse_rev_path {
39
+  my ($self, $user, $project, $rev_path) = @_;
40
+  
41
+  # References
42
+  my @cmd = $self->cmd(
43
+    $user,
44
+    $project,
45
+    'show-ref',
46
+    '--dereference'
47
+  );
48
+  open my $fh, '-|', @cmd
49
+    or return;
50
+  my $refs = [];
51
+  while (my $line = $self->_dec(scalar <$fh>)) {
52
+    chomp $line;
53
+    if ($line =~ m!^[0-9a-fA-F]{40}\s(refs/((?:heads|tags)/(.*)))$!) {
54
+      push @$refs, $1, $2, $3;
55
+    }
56
+  }
57
+  close $fh or return;
58
+  
59
+  @$refs = sort {
60
+    my @a_match = $a =~ /(\/)/g;
61
+    my @b_match = $b =~ /(\/)/g;
62
+    scalar @b_match <=> scalar @a_match;
63
+  } @$refs;
64
+  
65
+  for my $ref (@$refs) {
66
+    $rev_path =~ m#/$#;
67
+    if ($rev_path =~ m#^(\Q$ref\E)/(.+)#) {
68
+      my $rev = $1;
69
+      my $path = $2;
70
+      return ($rev, $path);
71
+    }
72
+    elsif ($rev_path eq $ref) {
73
+      return ($rev_path, '');
74
+    }
75
+  }
76
+  
77
+  if ($rev_path) {
78
+    my ($rev, $path) = split /\//, $rev_path, 2;
79
+    $path = '' unless defined $path;
80
+    return ($rev, $path);
81
+  }
82
+
83
+  return;
84
+}
85
+
38 86
 sub authors {
39 87
   my ($self, $user, $project, $rev, $file) = @_;
40 88
   
... ...
@@ -692,9 +740,10 @@ sub references {
692 740
   
693 741
   # Parse references
694 742
   my %refs;
743
+  my $type_re = $type ? $type : '(?:heads|tags)';
695 744
   while (my $line = $self->_dec(scalar <$fh>)) {
696 745
     chomp $line;
697
-    if ($line =~ m!^([0-9a-fA-F]{40})\srefs/$type/(.*)$!) {
746
+    if ($line =~ m!^([0-9a-fA-F]{40})\srefs/$type_re/(.*)$!) {
698 747
       if (defined $refs{$1}) { push @{$refs{$1}}, $2 }
699 748
       else { $refs{$1} = [$2] }
700 749
     }
... ...
@@ -1196,7 +1245,7 @@ sub get_commits {
1196 1245
     ('--skip=' . $skip),
1197 1246
     $cid,
1198 1247
     '--',
1199
-    (defined $file ? ($file) : ())
1248
+    (defined $file && length $file ? ($file) : ())
1200 1249
   );
1201 1250
   open my $fh, '-|', @cmd
1202 1251
     or croak 'Open git-rev-list failed';
+6 -6
templates/blob.html.ep
... ...
@@ -1,15 +1,15 @@
1 1
 <%
2 2
   # API
3 3
   my $api = gitprep_api;
4
+
5
+  # Git
6
+  my $git = $self->app->git;
4 7
   
5 8
   # Parameters
6 9
   my $user = param('user');
7 10
   my $project = param('project');
8
-  my $rev = param('rev');
9
-  my $file = param('file');
10
-
11
-  # Git
12
-  my $git = $self->app->git;
11
+  my $rev_file = param('rev_file');
12
+  my ($rev, $file) = $git->parse_rev_path($user, $project, $rev_file);
13 13
 
14 14
   # Commit
15 15
   my $commit = $git->last_change_commit($user, $project, $rev, $file);
... ...
@@ -31,7 +31,7 @@
31 31
   my $mimetype = $git->blob_mimetype($user, $project, $rev, $file);
32 32
 
33 33
   # Variables for included template
34
-  stash(id => $rev, project => $project);
34
+  stash(id => $rev, project => $project, rev => $rev);
35 35
 %>
36 36
 
37 37
 % layout 'common' , stylesheets => ['/js/google-code-prettify/prettify.css'];
+1
templates/commit.html.ep
... ...
@@ -56,6 +56,7 @@
56 56
   stash(
57 57
     from_id => $from_id,
58 58
     id => $id,
59
+    rev => $id,
59 60
     commit => $commit
60 61
   );
61 62
 %>
+9 -9
templates/commits.html.ep
... ...
@@ -2,16 +2,16 @@
2 2
   # API
3 3
   my $api = gitprep_api;
4 4
 
5
+  # Git
6
+  my $git = $self->app->git;
7
+
5 8
   # Parameters
6 9
   my $user = param('user');
7 10
   my $project = param('project');
8
-  my $rev = param('rev');
9
-  my $blob = param('blob');
11
+  my $rev_file = param('rev_file');
12
+  my ($rev, $file) = $git->parse_rev_path($user, $project, $rev_file);
10 13
   my $page = param('page') || 0;
11 14
   
12
-  # Git
13
-  my $git = $self->app->git;
14
-  
15 15
   # Commit
16 16
   my $commit = $git->get_commit($user, $project, $rev);
17 17
   
... ...
@@ -23,7 +23,7 @@
23 23
     $commit->{id},
24 24
     $page_count,
25 25
     $page_count * $page,
26
-    $blob
26
+    $file
27 27
   );
28 28
   my $commits_count = @$commits;
29 29
   my $commits_date = {};
... ...
@@ -34,7 +34,7 @@
34 34
   }
35 35
   
36 36
   # Global variable
37
-  stash(user => $user, project => $project);
37
+  stash(user => $user, project => $project, rev => $rev);
38 38
 %>
39 39
 
40 40
 % layout 'common';
... ...
@@ -46,8 +46,8 @@
46 46
     %= include '/include/code_menu', display => 'commits';
47 47
         
48 48
     <div style="margin-top:20px;margin-bottom:15px">
49
-      % if (defined $blob) {
50
-        %= include '/include/page_path', type => 'blob', Path => $blob, operation => 'commits', prefix => 'History for';
49
+      % if (defined $file) {
50
+        %= include '/include/page_path', type => 'blob', Path => $file, operation => 'commits', prefix => 'History for';
51 51
       % } else {
52 52
         <div style="font-size:18px">
53 53
           <a class="ubar" href="<%= url_for("/$user/$project") %>">
+1 -1
templates/compare.html.ep
... ...
@@ -113,7 +113,7 @@
113 113
     <h2>Compare View</h2>
114 114
     <div class="well" style="padding:9px 10px 9px 10px;margin-bottom:5px;position:relative">
115 115
       <div class="row">
116
-        <div class="span3">
116
+        <div class="span8">
117 117
           <button id="base-branch-btn" class="btn" style="padding:2px 10px">
118 118
             <%= $rev1 %>
119 119
           </button>
+2 -1
templates/include/code_menu.html.ep
... ...
@@ -1,6 +1,7 @@
1 1
 <%
2 2
   my $display = stash('display') || '';
3 3
   my $rev = stash('rev');
4
+  $rev = '' unless defined $rev;
4 5
   my $branches = stash('branches');
5 6
   my $branches_count = app->git->branches_count($user, $project);
6 7
   my $default_branch_name = app->manager->default_branch($user, $project);
... ...
@@ -98,7 +99,7 @@
98 99
       <%
99 100
         my $title;
100 101
         my $rev_short;
101
-        if (length $rev == 40) {
102
+        if (defined $rev && length $rev == 40) {
102 103
           $title = 'tree';
103 104
           $rev_short = substr($rev, 0, 10);
104 105
         }
+5 -5
templates/raw.html.ep
... ...
@@ -1,12 +1,12 @@
1 1
 <%
2
+  # Git
3
+  my $git = app->git;
4
+
2 5
   # Parameters
3 6
   my $user = param('user');
4 7
   my $project = param('project');
5
-  my $rev = param('rev');
6
-  my $file = param('file');
7
-
8
-  # Git
9
-  my $git = app->git;
8
+  my $rev_file = param('rev_file');
9
+  my ($rev, $file) = $git->parse_rev_path($user, $project, $rev_file);
10 10
   
11 11
   # Blob raw
12 12
   my $blob_raw = $git->blob_raw($user, $project, $rev, $file);
+7 -7
templates/tree.html.ep
... ...
@@ -1,15 +1,15 @@
1 1
 <%
2 2
   # API
3 3
   my $api = gitprep_api;
4
+
5
+  # Git
6
+  my $git = app->git;
4 7
   
5 8
   # Parameters
6 9
   my $user = param('user');
7 10
   my $project = param('project');
8
-  my $rev = param('rev');
9
-  my $dir = param('dir');
10
-
11
-  # Git
12
-  my $git = app->git;
11
+  my $rev_dir = param('rev_dir');
12
+  my ($rev, $dir) = $git->parse_rev_path($user, $project, $rev_dir);
13 13
   
14 14
   # Tree id
15 15
   my $commit = $git->get_commit($user, $project, $rev);
... ...
@@ -24,10 +24,10 @@
24 24
   
25 25
   # Variable for included templates
26 26
   stash(
27
-    rev => $rev,
28 27
     commit => $commit,
29 28
     trees => $trees,
30
-    dir => $dir,
29
+    rev => $rev,
30
+    dir => $dir
31 31
   );
32 32
 %>
33 33
 
+181 -61
xt/basic.t
... ...
@@ -69,43 +69,81 @@ note 'Project page';
69 69
   $t->content_like(qr#/$user/$project/blob/master/README#);
70 70
 }
71 71
 
72
-note 'Commit page - first commit';
72
+note 'Commit page';
73 73
 {
74
-  # Page access
75
-  $t->get_ok("/$user/$project/commit/4b0e81c462088b16fefbe545e00b993fd7e6f884");
76
-  
77
-  # Commit message
78
-  $t->content_like(qr/first commit/);
79
-  
80
-  # Commit datetime
81
-  $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
82
-  
83
-  # Parent not eixsts
84
-  $t->content_like(qr/0 <span .*?>parent/);
85
-  
86
-  # Commit id
87
-  $t->content_like(qr/4b0e81c462088b16fefbe545e00b993fd7e6f884/);
88
-  
89
-  # Author
90
-  $t->content_like(qr/Yuki Kimoto/);
91
-  
92
-  # File change count
93
-  $t->content_like(qr/1 changed files/);
94
-  
95
-  # Added README
96
-  $t->content_like(qr/class="file-add".*?README/s);
97
-  
98
-  # Empty file is added
99
-  $t->content_like(qr/No changes/);
74
+  {
75
+    # Page access
76
+    $t->get_ok("/$user/$project/commit/4b0e81c462088b16fefbe545e00b993fd7e6f884");
77
+    
78
+    # Commit message
79
+    $t->content_like(qr/first commit/);
80
+    
81
+    # Commit datetime
82
+    $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
83
+    
84
+    # Parent not eixsts
85
+    $t->content_like(qr/0 <span .*?>parent/);
86
+    
87
+    # Commit id
88
+    $t->content_like(qr/4b0e81c462088b16fefbe545e00b993fd7e6f884/);
89
+    
90
+    # Author
91
+    $t->content_like(qr/Yuki Kimoto/);
92
+    
93
+    # File change count
94
+    $t->content_like(qr/1 changed files/);
95
+    
96
+    # Added README
97
+    $t->content_like(qr/class="file-add".*?README/s);
98
+    
99
+    # Empty file is added
100
+    $t->content_like(qr/No changes/);
101
+  }
102
+  {
103
+    # Page access (branch name)
104
+    $t->get_ok("/$user/$project/commit/b1");
105
+    $t->content_like(qr/\+bbb/);
106
+  }
107
+  {
108
+    # Page access (branch name long)
109
+    $t->get_ok("/$user/$project/commit/refs/heads/b1");
110
+    $t->content_like(qr/\+bbb/);
111
+    $t->content_like(qr#refs/heads/b1#);
112
+  }
100 113
 }
101 114
 
102 115
 note 'Commits page';
103 116
 {
104
-  # Page access
105
-  $t->get_ok("/$user/$project/commits/master");
106
-  
107
-  # Commit date time
108
-  $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
117
+  {
118
+    # Page access
119
+    $t->get_ok("/$user/$project/commits/master");
120
+    
121
+    # Commit date time
122
+    $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
123
+  }
124
+  {
125
+    # Page access(branch name long)
126
+    $t->get_ok("/$user/$project/commits/refs/heads/master");
127
+    $t->content_like(qr#refs/heads/master#);
128
+  }
129
+}
130
+
131
+note 'History page';
132
+{
133
+  {
134
+    # Page access
135
+    $t->get_ok("/$user/$project/commits/b1/README");
136
+    
137
+    # Content
138
+    $t->content_like(qr/first commit/);
139
+  }
140
+  {
141
+    # Page access (branch name long)
142
+    $t->get_ok("/$user/$project/commits/refs/heads/b1/README");
143
+    
144
+    # Content
145
+    $t->content_like(qr/first commit/);
146
+  }
109 147
 }
110 148
 
111 149
 note 'Tags page';
... ...
@@ -131,43 +169,113 @@ note 'Tags page';
131 169
 
132 170
 note 'Tree page';
133 171
 {
134
-  # Page access
135
-  $t->get_ok("/$user/$project/tree/e891266d8aeab864c8eb36b7115416710b2cdc2e");
136
-  
137
-  # Commit datetime
138
-  $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
139
-  
140
-  # README
141
-  $t->content_like(qr/README.*bbb/s);
142
-  
143
-  # tree directory link
144
-  $t->content_like(qr#/$user/$project/tree/e891266d8aeab864c8eb36b7115416710b2cdc2e/dir#);
172
+  {
173
+    # Page access (hash)
174
+    $t->get_ok("/$user/$project/tree/e891266d8aeab864c8eb36b7115416710b2cdc2e");
175
+    
176
+    # Commit datetime
177
+    $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
178
+    
179
+    # README
180
+    $t->content_like(qr/README.*bbb/s);
181
+    
182
+    # tree directory link
183
+    $t->content_like(qr#/$user/$project/tree/e891266d8aeab864c8eb36b7115416710b2cdc2e/dir#);
145 184
 
146
-  # tree file link
147
-  $t->content_like(qr#/$user/$project/blob/e891266d8aeab864c8eb36b7115416710b2cdc2e/README#);
185
+    # tree file link
186
+    $t->content_like(qr#/$user/$project/blob/e891266d8aeab864c8eb36b7115416710b2cdc2e/README#);
187
+  }
188
+  {
189
+    # Page access (branch name)
190
+    $t->get_ok("/$user/$project/tree/b21/dir");
191
+    
192
+    # File
193
+    $t->content_like(qr/b\.txt/s);
194
+  }
195
+  {
196
+    # Page access (branch name middle)
197
+    $t->get_ok("/$user/$project/tree/heads/b21/dir");
198
+    
199
+    # File
200
+    $t->content_like(qr/b\.txt/s);
201
+  }
202
+  {
203
+    # Page access (branch name long)
204
+    $t->get_ok("/$user/$project/tree/refs/heads/b21/dir");
205
+    $t->content_like(qr#refs/heads/b21#);
206
+    
207
+    # File
208
+    $t->content_like(qr/b\.txt/s);
209
+  }
148 210
 }
149 211
 
150 212
 note 'Blob page';
151 213
 {
152
-  # Page access
153
-  $t->get_ok("/$user/$project/blob/b9f0f107672b910a44d22d4623ce7445d40565aa/a_renamed.txt");
154
-  
155
-  # Commit datetime
156
-  $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
157
-  
158
-  # Content
159
-  $t->content_like(qr/あああ/);
160
-}
214
+  {
215
+    # Page access (hash)
216
+    $t->get_ok("/$user/$project/blob/b9f0f107672b910a44d22d4623ce7445d40565aa/a_renamed.txt");
217
+    
218
+    # Commit datetime
219
+    $t->content_like(qr/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/);
220
+    
221
+    # Content
222
+    $t->content_like(qr/あああ/);
223
+  }
224
+  {
225
+    # Page access (branch name)
226
+    $t->get_ok("/$user/$project/blob/b1/README");
227
+    
228
+    # Content
229
+    $t->content_like(qr/bbb/);
230
+  }
231
+  {
232
+    # Page access (branch name middle)
233
+    $t->get_ok("/$user/$project/blob/heads/b1/README");
234
+    
235
+    # Content
236
+    $t->content_like(qr/bbb/);
237
+  }
238
+  {
239
+    # Page access (branch name long)
240
+    $t->get_ok("/$user/$project/blob/refs/heads/b1/README");
241
+    $t->content_like(qr#refs/heads/b1#);
242
+    
243
+    # Content
244
+    $t->content_like(qr/bbb/);
245
+  }}
161 246
 
162 247
 note 'raw page';
163 248
 {
164
-  # Page access
165
-  $t->get_ok("/$user/$project/raw/b9f0f107672b910a44d22d4623ce7445d40565aa/a_renamed.txt");
166
-  
167
-  # Content
168
-  my $content_binary = $t->tx->res->body;
169
-  my $content = decode('UTF-8', $content_binary);
170
-  like($content, qr/あああ/);
249
+  {
250
+    # Page access (hash)
251
+    $t->get_ok("/$user/$project/raw/b9f0f107672b910a44d22d4623ce7445d40565aa/a_renamed.txt");
252
+    
253
+    # Content
254
+    my $content_binary = $t->tx->res->body;
255
+    my $content = decode('UTF-8', $content_binary);
256
+    like($content, qr/あああ/);
257
+  }
258
+  {
259
+    # Page access (branch name)
260
+    $t->get_ok("/$user/$project/raw/b21/dir/b.txt");
261
+    
262
+    my $content = $t->tx->res->body;
263
+    like($content, qr/aaaa/);
264
+  }
265
+  {
266
+    # Page access (branch name middle)
267
+    $t->get_ok("/$user/$project/raw/heads/b21/dir/b.txt");
268
+    
269
+    my $content = $t->tx->res->body;
270
+    like($content, qr/aaaa/);
271
+  }
272
+  {
273
+    # Page access (branch name long)
274
+    $t->get_ok("/$user/$project/raw/refs/heads/b21/dir/b.txt");
275
+    
276
+    my $content = $t->tx->res->body;
277
+    like($content, qr/aaaa/);
278
+  }
171 279
 }
172 280
 
173 281
 note 'Aarchive';
... ...
@@ -180,3 +288,15 @@ note 'Aarchive';
180 288
   $t->get_ok("/$user/$project/archive/t1.tar.gz");
181 289
   $t->content_type_is('application/x-tar');
182 290
 }
291
+
292
+note 'Compare page';
293
+{
294
+  # Page access (branch name)
295
+  $t->get_ok("/$user/$project/compare/b1...master");
296
+  $t->content_like(qr#renamed dir/a\.txt to dir/b\.txt and added text#);
297
+
298
+  # Page access (branch name long)
299
+  $t->get_ok("/$user/$project/compare/refs/heads/b1...refs/heads/master");
300
+  $t->content_like(qr#renamed dir/a\.txt to dir/b\.txt and added text#);
301
+
302
+}