Showing 5 changed files with 224 additions and 162 deletions
+2 -2
lib/Gitprep.pm
... ...
@@ -224,8 +224,8 @@ sub startup {
224 224
         # Network Graph
225 225
         $r->get('/network/graph/(*rev1)...(*rev2_abs)' => template '/network/graph');
226 226
 
227
-        # Pull
228
-        $r->get('/pull/(*rev1)...(*rev2_abs)' => template '/pull');
227
+        # Import branch
228
+        $r->any('/import-branch/(*rev1)...(*rev2_abs)' => template '/import-branch');
229 229
         
230 230
         # Get branches and tags
231 231
         $r->get('/api/revs' => template '/api/revs');
+89 -67
lib/Gitprep/Git.pm
... ...
@@ -1405,6 +1405,28 @@ sub parse_ls_tree_line {
1405 1405
   return \%res;
1406 1406
 }
1407 1407
 
1408
+sub import_branch {
1409
+  my ($self, $user, $project, $branch, $remote_user, $remote_project, $remote_branch) = @_;
1410
+  
1411
+  # Git pull
1412
+  my $remote_rep = $self->rep($remote_user, $remote_project);
1413
+  my @cmd = $self->cmd(
1414
+    $user,
1415
+    $project,
1416
+    'fetch',
1417
+    $remote_rep,
1418
+    "refs/heads/$remote_branch:refs/heads/$branch"
1419
+  );
1420
+  open my $fh, '-|', @cmd
1421
+    or croak 'Open git fetch failed';
1422
+  
1423
+  # Output
1424
+  local $/ = "\0";
1425
+  my $content = $self->_dec(scalar <$fh>);
1426
+  warn $content;
1427
+  close $fh or croak "Can't read git fetch result";
1428
+}
1429
+
1408 1430
 sub search_bin {
1409 1431
   my $self = shift;
1410 1432
   
... ...
@@ -1486,6 +1508,73 @@ sub snapshot_name {
1486 1508
   return wantarray ? ($name, $name) : $name;
1487 1509
 }
1488 1510
 
1511
+sub timestamp {
1512
+  my ($self, $date) = @_;
1513
+  
1514
+  # Time stamp
1515
+  my $strtime = $date->{rfc2822};
1516
+  my $localtime_format = '(%02d:%02d %s)';
1517
+  if ($date->{hour_local} < 6) { $localtime_format = '(%02d:%02d %s)' }
1518
+  $strtime .= ' ' . sprintf(
1519
+    $localtime_format,
1520
+    $date->{hour_local},
1521
+    $date->{minute_local},
1522
+    $date->{tz_local}
1523
+  );
1524
+
1525
+  return $strtime;
1526
+}
1527
+
1528
+sub trees {
1529
+  my ($self, $user, $project, $rev, $dir) = @_;
1530
+  $dir = '' unless defined $dir;
1531
+  
1532
+  # Get tree
1533
+  my $tid;
1534
+  if (defined $dir && $dir ne '') {
1535
+    $tid = $self->path_to_hash($user, $project, $rev, $dir, 'tree');
1536
+  }
1537
+  else {
1538
+    my $commit = $self->get_commit($user, $project, $rev);
1539
+    $tid = $commit->{tree};
1540
+  }
1541
+  my @entries = ();
1542
+  my $show_sizes = 0;
1543
+  my @cmd = $self->cmd(
1544
+    $user,
1545
+    $project,
1546
+    'ls-tree',
1547
+    '-z',
1548
+    ($show_sizes ? '-l' : ()),
1549
+    $tid
1550
+  );
1551
+  open my $fh, '-|', @cmd
1552
+    or $self->croak('Open git-ls-tree failed');
1553
+  {
1554
+    local $/ = "\0";
1555
+    @entries = map { chomp; $self->_dec($_) } <$fh>;
1556
+  }
1557
+  close $fh
1558
+    or $self->croak(404, "Reading tree failed");
1559
+
1560
+  # Parse tree
1561
+  my $trees;
1562
+  for my $line (@entries) {
1563
+    my $tree = $self->parse_ls_tree_line($line, -z => 1, -l => $show_sizes);
1564
+    $tree->{mode_str} = $self->_mode_str($tree->{mode});
1565
+    
1566
+    # Commit log
1567
+    my $path = defined $dir && $dir ne '' ? "$dir/$tree->{name}" : $tree->{name};
1568
+    my $commit = $self->last_change_commit($user, $project, $rev, $path);
1569
+    $tree->{commit} = $commit;
1570
+    
1571
+    push @$trees, $tree;
1572
+  }
1573
+  $trees = [sort {$b->{type} cmp $a->{type} || $a->{name} cmp $b->{name}} @$trees];
1574
+  
1575
+  return $trees;
1576
+}
1577
+
1489 1578
 sub _age_string {
1490 1579
   my ($self, $age) = @_;
1491 1580
   my $age_str;
... ...
@@ -1569,73 +1658,6 @@ sub _chop_str {
1569 1658
   }
1570 1659
 }
1571 1660
 
1572
-sub timestamp {
1573
-  my ($self, $date) = @_;
1574
-  
1575
-  # Time stamp
1576
-  my $strtime = $date->{rfc2822};
1577
-  my $localtime_format = '(%02d:%02d %s)';
1578
-  if ($date->{hour_local} < 6) { $localtime_format = '(%02d:%02d %s)' }
1579
-  $strtime .= ' ' . sprintf(
1580
-    $localtime_format,
1581
-    $date->{hour_local},
1582
-    $date->{minute_local},
1583
-    $date->{tz_local}
1584
-  );
1585
-
1586
-  return $strtime;
1587
-}
1588
-
1589
-sub trees {
1590
-  my ($self, $user, $project, $rev, $dir) = @_;
1591
-  $dir = '' unless defined $dir;
1592
-  
1593
-  # Get tree
1594
-  my $tid;
1595
-  if (defined $dir && $dir ne '') {
1596
-    $tid = $self->path_to_hash($user, $project, $rev, $dir, 'tree');
1597
-  }
1598
-  else {
1599
-    my $commit = $self->get_commit($user, $project, $rev);
1600
-    $tid = $commit->{tree};
1601
-  }
1602
-  my @entries = ();
1603
-  my $show_sizes = 0;
1604
-  my @cmd = $self->cmd(
1605
-    $user,
1606
-    $project,
1607
-    'ls-tree',
1608
-    '-z',
1609
-    ($show_sizes ? '-l' : ()),
1610
-    $tid
1611
-  );
1612
-  open my $fh, '-|', @cmd
1613
-    or $self->croak('Open git-ls-tree failed');
1614
-  {
1615
-    local $/ = "\0";
1616
-    @entries = map { chomp; $self->_dec($_) } <$fh>;
1617
-  }
1618
-  close $fh
1619
-    or $self->croak(404, "Reading tree failed");
1620
-
1621
-  # Parse tree
1622
-  my $trees;
1623
-  for my $line (@entries) {
1624
-    my $tree = $self->parse_ls_tree_line($line, -z => 1, -l => $show_sizes);
1625
-    $tree->{mode_str} = $self->_mode_str($tree->{mode});
1626
-    
1627
-    # Commit log
1628
-    my $path = defined $dir && $dir ne '' ? "$dir/$tree->{name}" : $tree->{name};
1629
-    my $commit = $self->last_change_commit($user, $project, $rev, $path);
1630
-    $tree->{commit} = $commit;
1631
-    
1632
-    push @$trees, $tree;
1633
-  }
1634
-  $trees = [sort {$b->{type} cmp $a->{type} || $a->{name} cmp $b->{name}} @$trees];
1635
-  
1636
-  return $trees;
1637
-}
1638
-
1639 1661
 sub _dec {
1640 1662
   my ($self, $str) = @_;
1641 1663
   
+129
templates/import-branch.html.ep
... ...
@@ -0,0 +1,129 @@
1
+<%
2
+  my $user = param('user');
3
+  my $project = param('project');
4
+  my $branch = param('rev1');
5
+  my $rev2_abs = param('rev2_abs');
6
+  my ($remote_user, $remote_project, $remote_branch) = split /\//, $rev2_abs, 3;
7
+  
8
+  # Branches
9
+  my $git = app->git;
10
+  my $branches = $git->branches($user, $project);
11
+  my $branch_names = [map { $_->{name} } @$branches];
12
+  my $remote_branches = $git->branches($remote_user, $remote_project);
13
+  my $remote_branch_names = [map { $_->{name} } @$remote_branches];
14
+  
15
+  my $op = param('op') || '';
16
+  my $errors;
17
+  if ($op eq 'pull' && lc $self->req->method eq 'post') {
18
+  
19
+    # Validation
20
+    my $api = gitprep_api;
21
+    my $params = $api->params;
22
+    my $rule = [
23
+      user => [
24
+        'user_name'
25
+      ],
26
+      project => [
27
+        'project_name'
28
+      ],
29
+      branch => [
30
+        'any'
31
+      ],
32
+      remote_user => [
33
+        'user_name'
34
+      ],
35
+      remote_project => [
36
+        'project_name'
37
+      ],
38
+      remote_branch => [
39
+        'any'
40
+      ]
41
+    ];
42
+    my $vresult = app->validator->validate($params, $rule);
43
+    
44
+    if ($vresult->is_ok) {
45
+      my $safe_params = $vresult->data;
46
+      
47
+      my $user = $safe_params->{user};
48
+      my $project = $safe_params->{project};
49
+      my $branch = $safe_params->{branch};
50
+      my $remote_user = $safe_params->{remote_user};
51
+      my $remote_project = $safe_params->{remote_project};
52
+      my $remote_branch = $safe_params->{remote_branch};
53
+      
54
+      $git->import_branch(
55
+        $user,
56
+        $project,
57
+        $branch,
58
+        $remote_user,
59
+        $remote_project,
60
+        $remote_branch
61
+      );
62
+    }
63
+    else {
64
+      $errors = ['Parameter is invalid'];
65
+    }
66
+  }
67
+%>
68
+
69
+% layout 'common', title => "Import branch";
70
+  %= include 'include/header';
71
+  
72
+  %= javascript begin
73
+    $('document').ready(function () {
74
+      
75
+      // Select remote branch
76
+      $('[name=copy-branch-name]').on('click', function () {
77
+        $('[name=branch]').val($('[name=remote_branch]').val());
78
+        return false;
79
+      });
80
+    });
81
+  % end
82
+  
83
+  <div class="container">
84
+    % if ($errors) {
85
+      <div class="alert alert-error">
86
+        <button type="button" class="close" data-dismiss="alert">&times;</button>
87
+        % for my $error (@$errors) {
88
+          <p><%= $error %></p>
89
+        % }
90
+      </div>
91
+    % }
92
+    <h3>Import branch</h3>
93
+    <form action="<%= url_for->query(op => 'import') %>" method="post">
94
+      <div class="row" style="font-size:22px">
95
+        <div class="span5">
96
+          <div class="well" style="text-align:center">
97
+            <div style="color:blue;margin-bottom:15px">
98
+              %= "$user / $project";
99
+            </div>
100
+            <div>
101
+              %= text_field 'branch';
102
+            </div>
103
+            <button name="copy-branch-name", class="btn">Copy Branch Name</button>
104
+            %= submit_button 'Import', style => "width:100px", class => "btn";
105
+          </div>
106
+        </div>
107
+        <div class="span2">
108
+          <div style="padding: 19px;text-align:center;font-size:26px">
109
+            &lArr;
110
+          </div>
111
+        </div>
112
+        <div class="span5">
113
+          <div class="well" style="text-align:center">
114
+            <div style="color:green;margin-bottom:15px">
115
+              %= "$remote_user / $remote_project";
116
+            </div>
117
+            % param(remote_branch => $remote_branch);
118
+            %= select_field 'remote_branch' => $remote_branch_names;
119
+          </div>
120
+        </div>
121
+      </div>
122
+      %= hidden_field user => $user;
123
+      %= hidden_field project => $user;
124
+      %= hidden_field remote_user => $remote_user;
125
+      %= hidden_field remote_project => $remote_project;
126
+    </form>
127
+  </div>
128
+  
129
+  %= include '/include/footer';
+4 -4
templates/network.html.ep
... ...
@@ -36,15 +36,15 @@
36 36
           + remote_member + '/' + remote_project + '/' + remote_branch;
37 37
       });
38 38
 
39
-      // Click pull button
40
-      $('[name=pull-btn]').on('click', function () {
39
+      // Click import button
40
+      $('[name=import-btn]').on('click', function () {
41 41
         var branch = $('[name=branch]').val();
42 42
         var remote = $(this).closest('[name=remote]');
43 43
         var remote_member = remote.find('[name=remote-member]').text();
44 44
         var remote_project = remote.find('[name=remote-project]').text();
45 45
         var remote_branch = remote.find('[name=remote-branch]').val();
46 46
         
47
-        location.href = '<%= url_for("/$user/$project/pull/") %>' + branch + '...'
47
+        location.href = '<%= url_for("/$user/$project/import-branch/") %>' + branch + '...'
48 48
           + remote_member + '/' + remote_project + '/' + remote_branch;
49 49
       });
50 50
     });
... ...
@@ -80,7 +80,7 @@
80 80
             </div>
81 81
             <div class="text-right">
82 82
               <button name="compare-btn" class="btn" style="margin-top:5px">Compare</button>
83
-              <button name="pull-btn" class="btn" style="margin-top:5px">Pull</button>
83
+              <button name="import-btn" class="btn" style="margin-top:5px">Import</button>
84 84
             </div>
85 85
           </div>
86 86
           <hr style="margin:0">
-89
templates/pull.html.ep
... ...
@@ -1,89 +0,0 @@
1
-<%
2
-  my $user = param('user');
3
-  my $project = param('project');
4
-  my $branch = param('rev1');
5
-  my $rev2_abs = param('rev2_abs');
6
-  my ($remote_user, $remote_project, $remote_branch) = split /\//, $rev2_abs, 3;
7
-  
8
-  # Branches
9
-  my $git = app->git;
10
-  my $branches = $git->branches($user, $project);
11
-  my $branch_names = [map { $_->{name} } @$branches];
12
-  my $remote_branches = $git->branches($remote_user, $remote_project);
13
-  my $remote_branch_names = [map { $_->{name} } @$remote_branches];
14
-%>
15
-
16
-% layout 'common', title => "Pull $user/$project/$branch...$rev2_abs";
17
-  %= include 'include/header';
18
-  
19
-  %= javascript begin
20
-    $('document').ready(function () {
21
-      
22
-      // New button click
23
-      $('[name=new]').on('click', function () {
24
-        $('[name=branch_select]').val('');
25
-        $('[name=branch]').val('');
26
-        
27
-        return false;
28
-      });
29
-      
30
-      // Select branch
31
-      $('[name=branch_select]').on('change', function () {
32
-        var val = $(this).val();
33
-        if (val === '(New)') {
34
-          $('[name=branch]').val('');
35
-        }
36
-        else if (val === '(Same name)') {
37
-          $('[name=branch]').val($('[name=remote_branch]').val());
38
-        }
39
-        else {
40
-          $('[name=branch]').val($(this).val());
41
-        }
42
-      });
43
-      
44
-      // Select remote branch
45
-      $('[name=remote_branch]').on('change', function () {
46
-        if ($('[name=branch_select]').val() === '(Same name)') {
47
-          $('[name=branch]').val($(this).val());
48
-        }
49
-      });
50
-    });
51
-  % end
52
-  
53
-  <div class="container">
54
-    <h3>Pull</h3>
55
-    <form action="<%= url_for->query(op => 'pull') %>" method="post">
56
-      <div class="row" style="font-size:22px">
57
-        <div class="span5">
58
-          <div class="well" style="text-align:center">
59
-            <div style="color:blue;margin-bottom:15px">
60
-              %= "$user / $project";
61
-            </div>
62
-            % param(branch_select => $rev1);
63
-            %= select_field 'branch_select' => ['(New)', '(Same name)', @$branch_names];
64
-            <div>
65
-              % param(branch => $rev1);
66
-              %= text_field 'branch';
67
-            </div>
68
-            %= submit_button 'Pull', style => "width:100px", class => "btn", ;
69
-          </div>
70
-        </div>
71
-        <div class="span2">
72
-          <div style="padding: 19px;text-align:center;font-size:26px">
73
-            &lArr;
74
-          </div>
75
-        </div>
76
-        <div class="span5">
77
-          <div class="well" style="text-align:center">
78
-            <div style="color:green;margin-bottom:15px">
79
-              %= "$remote_user / $remote_project";
80
-            </div>
81
-            % param(remote_branch => $remote_branch);
82
-            %= select_field 'remote_branch' => $remote_branch_names;
83
-          </div>
84
-        </div>
85
-      </div>
86
-    </form>
87
-  </div>
88
-  
89
-  %= include '/include/footer';