Showing 6 changed files with 258 additions and 170 deletions
+72 -43
lib/Gitprep.pm
... ...
@@ -58,8 +58,80 @@ sub startup {
58 58
     }
59 59
   });
60 60
   
61
+  # DBI
62
+  my $db_file = $self->home->rel_file('db/gitprep.db');
63
+  my $dbi = DBIx::Custom->connect(
64
+    dsn => "dbi:SQLite:database=$db_file",
65
+    connector => 1,
66
+    option => {sqlite_unicode => 1}
67
+  );
68
+  $self->dbi($dbi);
69
+
70
+  # Create user table
71
+  eval {
72
+    my $sql = <<"EOS";
73
+create table user (
74
+  row_id integer primary key autoincrement,
75
+  id not null unique,
76
+  config not null
77
+);
78
+EOS
79
+    $dbi->execute($sql);
80
+  };
81
+  
82
+  # Create project table
83
+  eval {
84
+    my $sql = <<"EOS";
85
+create table project (
86
+  row_id integer primary key autoincrement,
87
+  user_id not null,
88
+  name not null,
89
+  config not null,
90
+  unique(user_id, name)
91
+);
92
+EOS
93
+    $dbi->execute($sql);
94
+  };
95
+  
96
+  # Model
97
+  my $models = [
98
+    {table => 'user', primary_key => 'id'},
99
+    {table => 'project', primary_key => ['user_id', 'name']}
100
+  ];
101
+  $dbi->create_model($_) for @$models;
102
+
103
+  # Fiter
104
+  $dbi->register_filter(json => sub {
105
+    my $value = shift;
106
+    
107
+    if (ref $value) {
108
+      return decode('UTF-8', Mojo::JSON->new->encode($value));
109
+    }
110
+    else {
111
+      return Mojo::JSON->new->decode(encode('UTF-8', $value));
112
+    }
113
+  });
114
+  
115
+  # Validator
116
+  my $validator = Validator::Custom->new;
117
+  $self->validator($validator);
118
+  
119
+  # Helper
120
+  $self->helper(gitprep_api => sub { Gitprep::API->new(shift) });
121
+  
61 122
   # Route
62 123
   my $r = $self->routes->route->to('main#');
124
+  
125
+  # DBViewer(only development)
126
+  if ($self->mode eq 'development') {
127
+    eval {
128
+      $self->plugin(
129
+        'DBViewer',
130
+        dsn => "dbi:SQLite:database=$db_file",
131
+        route => $r
132
+      );
133
+    };
134
+  }
63 135
 
64 136
   # Home
65 137
   $r->get('/')->to('#home');
... ...
@@ -124,49 +196,6 @@ sub startup {
124 196
     # Compare
125 197
     $r->get('/compare/(#rev1)...(#rev2)')->to('#compare');
126 198
   }
127
-  
128
-  # DBI
129
-  my $db_file = $self->home->rel_file('db/gitprep.db');
130
-  my $dbi = DBIx::Custom->connect(
131
-    dsn => "dbi:SQLite:database=$db_file",
132
-    connector => 1,
133
-    option => {sqlite_unicode => 1}
134
-  );
135
-
136
-  eval {
137
-  # Create table
138
-    my $sql = <<"EOS";
139
-create table user (
140
-  row_id integer primary key autoincrement,
141
-  id not null unique,
142
-  config not null
143
-);
144
-EOS
145
-    $dbi->execute($sql);
146
-  };
147
-  $self->dbi($dbi);
148
-  
149
-  # Model
150
-  $dbi->create_model({table => 'user', primary_key => 'id'});
151
-  
152
-  # Fiter
153
-  $dbi->register_filter(json => sub {
154
-    my $value = shift;
155
-    
156
-    if (ref $value) {
157
-      return decode('UTF-8', Mojo::JSON->new->encode($value));
158
-    }
159
-    else {
160
-      return Mojo::JSON->new->decode(encode('UTF-8', $value));
161
-    }
162
-  });
163
-  
164
-  # Validator
165
-  my $validator = Validator::Custom->new;
166
-  $self->validator($validator);
167
-  
168
-  # Helper
169
-  $self->helper(gitprep_api => sub { Gitprep::API->new(shift) });
170 199
 }
171 200
 
172 201
 1;
+137 -113
lib/Gitprep/Git.pm
... ...
@@ -5,7 +5,7 @@ use Carp 'croak';
5 5
 use File::Find 'find';
6 6
 use File::Basename qw/basename dirname/;
7 7
 use Fcntl ':mode';
8
-use File::Path 'mkpath';
8
+use File::Path qw/mkpath rmtree/;
9 9
 use File::Copy 'move';
10 10
 
11 11
 # Attributes
... ...
@@ -198,69 +198,6 @@ sub blob_size_kb {
198 198
   return $size_kb;
199 199
 }
200 200
 
201
-sub check_head_link {
202
-  my ($self, $dir) = @_;
203
-  
204
-  # Chack head
205
-  my $head_file = "$dir/HEAD";
206
-  return ((-e $head_file) ||
207
-    (-l $head_file && readlink($head_file) =~ /^refs\/heads\//));
208
-}
209
-
210
-sub _cmd {
211
-  my ($self, $user, $project, @cmd) = @_;
212
-  
213
-  my $home = $self->rep_home;
214
-  
215
-  my $rep = "$home/$user/$project.git";
216
-  
217
-  # Execute git command
218
-  return ($self->bin, "--git-dir=$rep", @cmd);
219
-}
220
-
221
-sub create_repository {
222
-  my ($self, $user, $project, $opts) = @_;
223
-  
224
-  # Repository
225
-  my $rep_home = $self->rep_home;
226
-  my $rep = "$rep_home/$user/$project.git";
227
-  mkpath $rep;
228
-    
229
-  # Git init
230
-  my @git_init_cmd = $self->_cmd($user, $project, 'init', '--bare');
231
-  system(@git_init_cmd) == 0
232
-    or croak "Can't execute git init";
233
-    
234
-  # Add git-daemon-export-ok
235
-  {
236
-    my $file = "$rep/git-daemon-export-ok";
237
-    open my $fh, '>', $file
238
-      or croak "Can't create git-daemon-export-ok: $!"
239
-  }
240
-  
241
-  # HTTP support
242
-  my @git_update_server_info_cmd = $self->_cmd(
243
-    $user,
244
-    $project,
245
-    '--bare',
246
-    'update-server-info'
247
-  );
248
-  system(@git_update_server_info_cmd) == 0
249
-    or croak "Can't execute git --bare update-server-info";
250
-  move("$rep/hooks/post-update.sample", "$rep/hooks/post-update")
251
-    or croak "Can't move post-update";
252
-  
253
-  # Description
254
-  if (my $description = $opts->{description}) {
255
-    my $file = "$rep/description";
256
-    open my $fh, '>', $file
257
-      or croak "Can't open $file: $!";
258
-    print $fh $description
259
-      or croak "Can't write $file: $!";
260
-    close $fh;
261
-  }
262
-}
263
-
264 201
 sub branch_exists {
265 202
   my ($self, $user, $project) = @_;
266 203
   
... ...
@@ -316,31 +253,63 @@ sub branch_commits {
316 253
   return $commits;
317 254
 }
318 255
 
319
-sub separated_commit {
320
-  my ($self, $user, $project, $rev1, $rev2) = @_;
256
+sub check_head_link {
257
+  my ($self, $dir) = @_;
321 258
   
322
-  # Command "git diff-tree"
323
-  my @cmd = $self->_cmd(
324
-    $user,
325
-    $project,
326
-    'show-branch',
327
-    $rev1,
328
-    $rev2
329
-  );
330
-  open my $fh, "-|", @cmd
331
-    or croak 500, "Open git-show-branch failed";
259
+  # Chack head
260
+  my $head_file = "$dir/HEAD";
261
+  return ((-e $head_file) ||
262
+    (-l $head_file && readlink($head_file) =~ /^refs\/heads\//));
263
+}
332 264
 
333
-  my $commits = [];
334
-  my $start;
335
-  my @lines = <$fh>;
336
-  my $last_line = pop @lines;
337
-  my $commit;
338
-  if (defined $last_line) {
339
-      my ($id) = $last_line =~ /^.*?\[(.+)?\]/;
340
-      $commit = $self->parse_commit($user, $project, $id);
341
-  }
265
+sub create_repository {
266
+  my ($self, $user, $project, $opts) = @_;
342 267
 
343
-  return $commit;
268
+  my $rep_home = $self->rep_home;
269
+  my $rep = "$rep_home/$user/$project.git";
270
+  eval {
271
+    # Repository
272
+    mkpath $rep;
273
+      
274
+    # Git init
275
+    my @git_init_cmd = $self->_cmd($user, $project, 'init', '--bare');
276
+    system(@git_init_cmd) == 0
277
+      or croak "Can't execute git init";
278
+      
279
+    # Add git-daemon-export-ok
280
+    {
281
+      my $file = "$rep/git-daemon-export-ok";
282
+      open my $fh, '>', $file
283
+        or croak "Can't create git-daemon-export-ok: $!"
284
+    }
285
+    
286
+    # HTTP support
287
+    my @git_update_server_info_cmd = $self->_cmd(
288
+      $user,
289
+      $project,
290
+      '--bare',
291
+      'update-server-info'
292
+    );
293
+    system(@git_update_server_info_cmd) == 0
294
+      or croak "Can't execute git --bare update-server-info";
295
+    move("$rep/hooks/post-update.sample", "$rep/hooks/post-update")
296
+      or croak "Can't move post-update";
297
+    
298
+    # Description
299
+    if (my $description = $opts->{description}) {
300
+      my $file = "$rep/description";
301
+      open my $fh, '>', $file
302
+        or croak "Can't open $file: $!";
303
+      print $fh $description
304
+        or croak "Can't write $file: $!";
305
+      close $fh;
306
+    }
307
+  };
308
+  if ($@) {
309
+    my $error = $@;
310
+    $self->remove_repository($user, $project);
311
+    die "$error\n";
312
+  }
344 313
 }
345 314
 
346 315
 sub commits_number {
... ...
@@ -363,6 +332,12 @@ sub commits_number {
363 332
   return $commits_num;
364 333
 }
365 334
 
335
+sub exists_repository {
336
+  my ($self, $user, $project) = @_;
337
+  
338
+  return -e $self->rep($user, $project);
339
+}
340
+
366 341
 sub file_type {
367 342
   my ($self, $mode) = @_;
368 343
   
... ...
@@ -732,6 +707,7 @@ sub projects {
732 707
       $rep->{age} = $activity[0];
733 708
       $rep->{age_string} = $activity[1];
734 709
     }
710
+    else { $rep->{age} = 0 }
735 711
     
736 712
     my $description = $self->description($user, $project) || '';
737 713
     $rep->{description} = $self->_chop_str($description, 25, 5);
... ...
@@ -1151,6 +1127,16 @@ sub parse_ls_tree_line {
1151 1127
   return \%res;
1152 1128
 }
1153 1129
 
1130
+sub remove_repository {
1131
+  my ($self, $user, $project) = @_;
1132
+
1133
+  my $rep_home = $self->rep_home;
1134
+  croak "Can't remove repository. repositry home is empty"
1135
+    if !defined $rep_home || $rep_home eq '';
1136
+  my $rep = "$rep_home/$user/$project.git";
1137
+  rmtree $rep;
1138
+}
1139
+
1154 1140
 sub search_bin {
1155 1141
   my $self = shift;
1156 1142
   
... ...
@@ -1175,6 +1161,33 @@ sub search_bin {
1175 1161
   return;
1176 1162
 }
1177 1163
 
1164
+sub separated_commit {
1165
+  my ($self, $user, $project, $rev1, $rev2) = @_;
1166
+  
1167
+  # Command "git diff-tree"
1168
+  my @cmd = $self->_cmd(
1169
+    $user,
1170
+    $project,
1171
+    'show-branch',
1172
+    $rev1,
1173
+    $rev2
1174
+  );
1175
+  open my $fh, "-|", @cmd
1176
+    or croak 500, "Open git-show-branch failed";
1177
+
1178
+  my $commits = [];
1179
+  my $start;
1180
+  my @lines = <$fh>;
1181
+  my $last_line = pop @lines;
1182
+  my $commit;
1183
+  if (defined $last_line) {
1184
+      my ($id) = $last_line =~ /^.*?\[(.+)?\]/;
1185
+      $commit = $self->parse_commit($user, $project, $id);
1186
+  }
1187
+
1188
+  return $commit;
1189
+}
1190
+
1178 1191
 sub snapshot_name {
1179 1192
   my ($self, $project, $cid) = @_;
1180 1193
 
... ...
@@ -1285,33 +1298,6 @@ sub _chop_str {
1285 1298
   }
1286 1299
 }
1287 1300
 
1288
-sub _mode_str {
1289
-  my $self = shift;
1290
-  my $mode = oct shift;
1291
-
1292
-  # Mode to string
1293
-  if ($self->_s_isgitlink($mode)) { return 'm---------' }
1294
-  elsif (S_ISDIR($mode & S_IFMT)) { return 'drwxr-xr-x' }
1295
-  elsif (S_ISLNK($mode)) { return 'lrwxrwxrwx' }
1296
-  elsif (S_ISREG($mode)) {
1297
-    if ($mode & S_IXUSR) {
1298
-      return '-rwxr-xr-x';
1299
-    } else {
1300
-      return '-rw-r--r--'
1301
-    }
1302
-  } else { return '----------' }
1303
-  
1304
-  return;
1305
-}
1306
-
1307
-sub _s_isgitlink {
1308
-  my ($self, $mode) = @_;
1309
-  
1310
-  # Check if git link
1311
-  my $s_ifgitlink = 0160000;
1312
-  return (($mode & S_IFMT) == $s_ifgitlink)
1313
-}
1314
-
1315 1301
 sub timestamp {
1316 1302
   my ($self, $date) = @_;
1317 1303
   
... ...
@@ -1370,6 +1356,44 @@ sub trees {
1370 1356
   return $trees;
1371 1357
 }
1372 1358
 
1359
+sub _cmd {
1360
+  my ($self, $user, $project, @cmd) = @_;
1361
+  
1362
+  my $home = $self->rep_home;
1363
+  
1364
+  my $rep = "$home/$user/$project.git";
1365
+  
1366
+  # Execute git command
1367
+  return ($self->bin, "--git-dir=$rep", @cmd);
1368
+}
1369
+
1370
+sub _mode_str {
1371
+  my $self = shift;
1372
+  my $mode = oct shift;
1373
+
1374
+  # Mode to string
1375
+  if ($self->_s_isgitlink($mode)) { return 'm---------' }
1376
+  elsif (S_ISDIR($mode & S_IFMT)) { return 'drwxr-xr-x' }
1377
+  elsif (S_ISLNK($mode)) { return 'lrwxrwxrwx' }
1378
+  elsif (S_ISREG($mode)) {
1379
+    if ($mode & S_IXUSR) {
1380
+      return '-rwxr-xr-x';
1381
+    } else {
1382
+      return '-rw-r--r--'
1383
+    }
1384
+  } else { return '----------' }
1385
+  
1386
+  return;
1387
+}
1388
+
1389
+sub _s_isgitlink {
1390
+  my ($self, $mode) = @_;
1391
+  
1392
+  # Check if git link
1393
+  my $s_ifgitlink = 0160000;
1394
+  return (($mode & S_IFMT) == $s_ifgitlink)
1395
+}
1396
+
1373 1397
 sub _slurp {
1374 1398
   my ($self, $file) = @_;
1375 1399
   
script/gitprep 1000644 → 1000755
File mode changed.
+42 -13
templates/admin/create.html.ep
... ...
@@ -1,5 +1,5 @@
1 1
 <%
2
-  my $op = param('op');
2
+  my $op = param('op') || '';
3 3
   
4 4
   my $errors;
5 5
   if ($op eq 'create') {
... ...
@@ -8,7 +8,7 @@
8 8
     
9 9
     # Validation
10 10
     my $params = $api->params;
11
-    my $project_check = sub {
11
+    my $keyword_check = sub {
12 12
       my $value = shift;
13 13
       
14 14
       return ($value || '') =~ /^[a-zA-Z0-9_\-]+$/
... ...
@@ -16,7 +16,7 @@
16 16
     my $rule = [
17 17
       project => [
18 18
         ['not_blank' => 'Repository name is empty'],
19
-        [$project_check => 'Invalid repository name']
19
+        [$keyword_check => 'Invalid repository name']
20 20
       ],
21 21
       description => [
22 22
         'any'
... ...
@@ -25,20 +25,49 @@
25 25
     my $validator = app->validator;
26 26
     my $vresult = $validator->validate($params, $rule);
27 27
     
28
+    # Git
29
+    my $git = app->git;
28 30
     if ($vresult->is_ok) {
29
-      my $user = session('user_id');
31
+      # Not logined
32
+      unless ($api->logined) {
33
+        return $self->render_exception;
34
+      }
35
+      
30 36
       my $data = $vresult->data;
37
+      my $user = session('user_id');
31 38
       my $project = $data->{project};
32 39
       my $description = $data->{description};
33
-      
34
-      app->git->create_repository(
35
-        $user,
36
-        $project,
37
-        {description => $description}
38
-      );
39
-      
40
-      $self->redirect_to("/$user/$project");
41
-      return 1;
40
+
41
+      if ($git->exists_repository($user, $project)) {
42
+        $errors = ['Repositry already exists'];
43
+      }
44
+      else {
45
+        # Create repository
46
+        eval {
47
+          $git->create_repository(
48
+            $user,
49
+            $project,
50
+            {description => $description}
51
+          );
52
+        };
53
+        $api->croak($@) if $@;
54
+        
55
+        # Create repository data
56
+        eval {
57
+          app->dbi->model('project')
58
+            ->insert({config => '{}'}, id => [$user, $project]);
59
+        };
60
+        if ($@) {
61
+          my $error = $@;
62
+          $git->remove_repository($user, $project);
63
+          $api->croak($error);
64
+        }
65
+        
66
+        # Go to user page
67
+        $self->redirect_to("/$user/$project");
68
+        
69
+        return 1;
70
+      }
42 71
     }
43 72
     else { $errors = $vresult->messages }
44 73
   }
+6
templates/include/footer.html.ep
... ...
@@ -2,3 +2,9 @@
2 2
 <div class="text-center" style="margin-bottom:10px">
3 3
   <a href="https://github.com/yuki-kimoto/gitprep">Gitprep</a>
4 4
 </div>
5
+
6
+% if (app->mode eq 'development') {
7
+  <div class="text-center">
8
+    <a href="<%= url_for('/dbviewer') %>">DBViewer</a>
9
+  </div>
10
+% }
+1 -1
templates/main/user.html.ep
... ...
@@ -19,7 +19,7 @@
19 19
       <h3>Repositories</h3>
20 20
       
21 21
       <table class="table">
22
-        % for my $rep (@$reps) {
22
+        % for my $rep (sort { $a->{age} <=> $b->{age} } @$reps) {
23 23
           <tr>
24 24
             % my $pname = $rep->{name};
25 25
               <td>