... | ... |
@@ -1,23 +1,22 @@ |
1 | 1 |
use 5.008007; |
2 | 2 |
package Gitprep; |
3 |
- |
|
4 | 3 |
use Mojo::Base 'Mojolicious'; |
5 |
-use Gitprep::Git; |
|
4 |
+ |
|
5 |
+use Carp 'croak'; |
|
6 | 6 |
use DBIx::Custom; |
7 |
-use Validator::Custom; |
|
8 | 7 |
use Encode qw/encode decode/; |
9 | 8 |
use Gitprep::API; |
10 |
-use Carp 'croak'; |
|
9 |
+use Gitprep::Git; |
|
11 | 10 |
use Gitprep::Manager; |
12 | 11 |
use Scalar::Util 'weaken'; |
13 |
-use Carp 'croak'; |
|
12 |
+use Validator::Custom; |
|
14 | 13 |
|
15 | 14 |
our $VERSION = '0.04'; |
16 | 15 |
|
17 |
-has 'git'; |
|
18 | 16 |
has 'dbi'; |
19 |
-has 'validator'; |
|
17 |
+has 'git'; |
|
20 | 18 |
has 'manager'; |
19 |
+has 'validator'; |
|
21 | 20 |
|
22 | 21 |
sub startup { |
23 | 22 |
my $self = shift; |
... | ... |
@@ -2,91 +2,39 @@ package Gitprep::Git; |
2 | 2 |
use Mojo::Base -base; |
3 | 3 |
|
4 | 4 |
use Carp 'croak'; |
5 |
-use File::Find 'find'; |
|
6 |
-use File::Basename qw/basename dirname/; |
|
5 |
+use Encode qw/encode decode/; |
|
7 | 6 |
use Fcntl ':mode'; |
8 |
-use File::Path qw/mkpath rmtree/; |
|
7 |
+use File::Basename qw/basename dirname/; |
|
9 | 8 |
use File::Copy 'move'; |
9 |
+use File::Find 'find'; |
|
10 |
+use File::Path qw/mkpath rmtree/; |
|
10 | 11 |
|
11 | 12 |
# Attributes |
12 | 13 |
has 'bin'; |
14 |
+has encoding => 'UTF-8'; |
|
13 | 15 |
has 'rep_home'; |
14 |
-has 'encoding' => 'UTF-8'; |
|
15 | 16 |
has text_exts => sub { ['txt'] }; |
16 | 17 |
|
17 |
-# Encode |
|
18 |
-use Encode qw/encode decode/; |
|
19 |
-sub _enc { |
|
20 |
- my ($self, $str) = @_; |
|
21 |
- |
|
22 |
- my $enc = $self->encoding; |
|
23 |
- |
|
24 |
- return encode($enc, $str); |
|
25 |
-} |
|
26 |
- |
|
27 |
-sub _dec { |
|
28 |
- my ($self, $str) = @_; |
|
29 |
- |
|
30 |
- my $enc = $self->encoding; |
|
18 |
+sub cmd { |
|
19 |
+ my ($self, $user, $project, @cmd) = @_; |
|
31 | 20 |
|
32 |
- my $new_str; |
|
33 |
- eval { $new_str = decode($enc, $str) }; |
|
21 |
+ # Git command |
|
22 |
+ my $home = $self->rep_home; |
|
23 |
+ my $rep = "$home/$user/$project.git"; |
|
34 | 24 |
|
35 |
- return $@ ? $str : $new_str; |
|
25 |
+ return $self->cmd_rep($rep, @cmd); |
|
36 | 26 |
} |
37 | 27 |
|
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 |
- } |
|
28 |
+sub cmd_rep { |
|
29 |
+ my ($self, $rep, @cmd) = @_; |
|
76 | 30 |
|
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; |
|
31 |
+ return ($self->bin, "--git-dir=$rep", @cmd); |
|
84 | 32 |
} |
85 | 33 |
|
86 | 34 |
sub authors { |
87 | 35 |
my ($self, $user, $project, $rev, $file) = @_; |
88 | 36 |
|
89 |
- # Command "git log FILE" |
|
37 |
+ # Authors |
|
90 | 38 |
my @cmd = $self->cmd( |
91 | 39 |
$user, |
92 | 40 |
$project, |
... | ... |
@@ -108,12 +56,11 @@ sub authors { |
108 | 56 |
} |
109 | 57 |
|
110 | 58 |
sub blobdiffs { |
111 |
- my ($self, $user, $project, $from_id, $id, $difftrees) = @_; |
|
59 |
+ my ($self, $user, $project, $rev1, $rev2, $difftrees) = @_; |
|
112 | 60 |
|
113 |
- return unless defined $from_id; |
|
61 |
+ return unless defined $rev1 && defined $rev2; |
|
114 | 62 |
|
115 |
- # Files changing infomation |
|
116 |
- my $blobdiffs = []; |
|
63 |
+ # Diff tree |
|
117 | 64 |
my @cmd = $self->cmd( |
118 | 65 |
$user, |
119 | 66 |
$project, |
... | ... |
@@ -122,8 +69,8 @@ sub blobdiffs { |
122 | 69 |
'-M', |
123 | 70 |
'--no-commit-id', |
124 | 71 |
'--patch-with-raw', |
125 |
- $from_id, |
|
126 |
- $id, |
|
72 |
+ $rev1, |
|
73 |
+ $rev2, |
|
127 | 74 |
'--' |
128 | 75 |
); |
129 | 76 |
open my $fh, '-|', @cmd |
... | ... |
@@ -135,15 +82,18 @@ sub blobdiffs { |
135 | 82 |
last if $line =~ /^\n/; |
136 | 83 |
} |
137 | 84 |
close $fh; |
85 |
+ |
|
86 |
+ # Blob diffs |
|
87 |
+ my $blobdiffs = []; |
|
138 | 88 |
for my $line (@file_info_raws) { |
139 | 89 |
|
140 |
- # Parse line |
|
90 |
+ # File information |
|
141 | 91 |
chomp $line; |
142 | 92 |
my $diffinfo = $self->parse_difftree_raw_line($line); |
143 | 93 |
my $from_file = $diffinfo->{from_file}; |
144 | 94 |
my $file = $diffinfo->{to_file}; |
145 | 95 |
|
146 |
- # Get blobdiff (command "self diff-tree") |
|
96 |
+ # Blob diff |
|
147 | 97 |
my @cmd = $self->cmd( |
148 | 98 |
$user, |
149 | 99 |
$project, |
... | ... |
@@ -151,8 +101,8 @@ sub blobdiffs { |
151 | 101 |
'-r', |
152 | 102 |
'-M', |
153 | 103 |
'-p', |
154 |
- $from_id, |
|
155 |
- $id, |
|
104 |
+ $rev1, |
|
105 |
+ $rev2, |
|
156 | 106 |
'--', |
157 | 107 |
(defined $from_file ? $from_file : ()), |
158 | 108 |
$file |
... | ... |
@@ -683,17 +633,6 @@ sub branches_count { |
683 | 633 |
return $branches_count; |
684 | 634 |
} |
685 | 635 |
|
686 |
-sub no_merged_branches_count { |
|
687 |
- my ($self, $user, $project) = @_; |
|
688 |
- |
|
689 |
- my @cmd = $self->cmd($user, $project, 'branch', '--no-merged'); |
|
690 |
- open my $fh, '-|', @cmd or return; |
|
691 |
- my @branches = <$fh>; |
|
692 |
- my $branches_count = @branches; |
|
693 |
- |
|
694 |
- return $branches_count; |
|
695 |
-} |
|
696 |
- |
|
697 | 636 |
sub id_by_path { |
698 | 637 |
my ($self, $user, $project, $rev, $path, $type) = @_; |
699 | 638 |
|
... | ... |
@@ -717,40 +656,43 @@ sub id_by_path { |
717 | 656 |
return $id; |
718 | 657 |
} |
719 | 658 |
|
720 |
-sub references { |
|
721 |
- my ($self, $user, $project, $type) = @_; |
|
722 |
- |
|
723 |
- $type ||= ''; |
|
659 |
+ |
|
660 |
+sub last_activity { |
|
661 |
+ my ($self, $user, $project) = @_; |
|
724 | 662 |
|
725 |
- # Branches or tags |
|
663 |
+ # Command "git for-each-ref" |
|
726 | 664 |
my @cmd = $self->cmd( |
727 | 665 |
$user, |
728 | 666 |
$project, |
729 |
- 'show-ref', |
|
730 |
- '--dereference', |
|
731 |
- ( |
|
732 |
- $type eq 'heads' ? ('--heads') : |
|
733 |
- $type eq 'tags' ? ('--tags') : |
|
734 |
- () |
|
735 |
- ) |
|
667 |
+ 'for-each-ref', |
|
668 |
+ '--format=%(committer)', |
|
669 |
+ '--sort=-committerdate', |
|
670 |
+ '--count=1', 'refs/heads' |
|
736 | 671 |
); |
672 |
+ open my $fh, '-|', @cmd or return; |
|
673 |
+ my $most_recent = $self->_dec(scalar <$fh>); |
|
674 |
+ close $fh or return; |
|
737 | 675 |
|
738 |
- open my $fh, '-|', @cmd |
|
739 |
- or return; |
|
740 |
- |
|
741 |
- # Parse references |
|
742 |
- my %refs; |
|
743 |
- my $type_re = $type ? $type : '(?:heads|tags)'; |
|
744 |
- while (my $line = $self->_dec(scalar <$fh>)) { |
|
745 |
- chomp $line; |
|
746 |
- if ($line =~ m!^([0-9a-fA-F]{40})\srefs/$type_re/(.*)$!) { |
|
747 |
- if (defined $refs{$1}) { push @{$refs{$1}}, $2 } |
|
748 |
- else { $refs{$1} = [$2] } |
|
749 |
- } |
|
676 |
+ # Parse most recent |
|
677 |
+ if (defined $most_recent && |
|
678 |
+ $most_recent =~ / (\d+) [-+][01]\d\d\d$/) { |
|
679 |
+ my $timestamp = $1; |
|
680 |
+ my $age = time - $timestamp; |
|
681 |
+ return ($age, $self->_age_string($age)); |
|
750 | 682 |
} |
751 |
- close $fh or return; |
|
752 | 683 |
|
753 |
- return \%refs; |
|
684 |
+ return; |
|
685 |
+} |
|
686 |
+ |
|
687 |
+sub no_merged_branches_count { |
|
688 |
+ my ($self, $user, $project) = @_; |
|
689 |
+ |
|
690 |
+ my @cmd = $self->cmd($user, $project, 'branch', '--no-merged'); |
|
691 |
+ open my $fh, '-|', @cmd or return; |
|
692 |
+ my @branches = <$fh>; |
|
693 |
+ my $branches_count = @branches; |
|
694 |
+ |
|
695 |
+ return $branches_count; |
|
754 | 696 |
} |
755 | 697 |
|
756 | 698 |
sub path_by_id { |
... | ... |
@@ -779,30 +721,51 @@ sub path_by_id { |
779 | 721 |
return; |
780 | 722 |
} |
781 | 723 |
|
782 |
-sub last_activity { |
|
783 |
- my ($self, $user, $project) = @_; |
|
724 |
+sub parse_rev_path { |
|
725 |
+ my ($self, $user, $project, $rev_path) = @_; |
|
784 | 726 |
|
785 |
- # Command "git for-each-ref" |
|
727 |
+ # References |
|
786 | 728 |
my @cmd = $self->cmd( |
787 | 729 |
$user, |
788 | 730 |
$project, |
789 |
- 'for-each-ref', |
|
790 |
- '--format=%(committer)', |
|
791 |
- '--sort=-committerdate', |
|
792 |
- '--count=1', 'refs/heads' |
|
731 |
+ 'show-ref', |
|
732 |
+ '--dereference' |
|
793 | 733 |
); |
794 |
- open my $fh, '-|', @cmd or return; |
|
795 |
- my $most_recent = $self->_dec(scalar <$fh>); |
|
734 |
+ open my $fh, '-|', @cmd |
|
735 |
+ or return; |
|
736 |
+ my $refs = []; |
|
737 |
+ while (my $line = $self->_dec(scalar <$fh>)) { |
|
738 |
+ chomp $line; |
|
739 |
+ if ($line =~ m!^[0-9a-fA-F]{40}\s(refs/((?:heads|tags)/(.*)))$!) { |
|
740 |
+ push @$refs, $1, $2, $3; |
|
741 |
+ } |
|
742 |
+ } |
|
796 | 743 |
close $fh or return; |
797 | 744 |
|
798 |
- # Parse most recent |
|
799 |
- if (defined $most_recent && |
|
800 |
- $most_recent =~ / (\d+) [-+][01]\d\d\d$/) { |
|
801 |
- my $timestamp = $1; |
|
802 |
- my $age = time - $timestamp; |
|
803 |
- return ($age, $self->_age_string($age)); |
|
745 |
+ @$refs = sort { |
|
746 |
+ my @a_match = $a =~ /(\/)/g; |
|
747 |
+ my @b_match = $b =~ /(\/)/g; |
|
748 |
+ scalar @b_match <=> scalar @a_match; |
|
749 |
+ } @$refs; |
|
750 |
+ |
|
751 |
+ for my $ref (@$refs) { |
|
752 |
+ $rev_path =~ m#/$#; |
|
753 |
+ if ($rev_path =~ m#^(\Q$ref\E)/(.+)#) { |
|
754 |
+ my $rev = $1; |
|
755 |
+ my $path = $2; |
|
756 |
+ return ($rev, $path); |
|
757 |
+ } |
|
758 |
+ elsif ($rev_path eq $ref) { |
|
759 |
+ return ($rev_path, ''); |
|
760 |
+ } |
|
804 | 761 |
} |
805 | 762 |
|
763 |
+ if ($rev_path) { |
|
764 |
+ my ($rev, $path) = split /\//, $rev_path, 2; |
|
765 |
+ $path = '' unless defined $path; |
|
766 |
+ return ($rev, $path); |
|
767 |
+ } |
|
768 |
+ |
|
806 | 769 |
return; |
807 | 770 |
} |
808 | 771 |
|
... | ... |
@@ -881,6 +844,42 @@ sub projects { |
881 | 844 |
return \@reps; |
882 | 845 |
} |
883 | 846 |
|
847 |
+sub references { |
|
848 |
+ my ($self, $user, $project, $type) = @_; |
|
849 |
+ |
|
850 |
+ $type ||= ''; |
|
851 |
+ |
|
852 |
+ # Branches or tags |
|
853 |
+ my @cmd = $self->cmd( |
|
854 |
+ $user, |
|
855 |
+ $project, |
|
856 |
+ 'show-ref', |
|
857 |
+ '--dereference', |
|
858 |
+ ( |
|
859 |
+ $type eq 'heads' ? ('--heads') : |
|
860 |
+ $type eq 'tags' ? ('--tags') : |
|
861 |
+ () |
|
862 |
+ ) |
|
863 |
+ ); |
|
864 |
+ |
|
865 |
+ open my $fh, '-|', @cmd |
|
866 |
+ or return; |
|
867 |
+ |
|
868 |
+ # Parse references |
|
869 |
+ my %refs; |
|
870 |
+ my $type_re = $type ? $type : '(?:heads|tags)'; |
|
871 |
+ while (my $line = $self->_dec(scalar <$fh>)) { |
|
872 |
+ chomp $line; |
|
873 |
+ if ($line =~ m!^([0-9a-fA-F]{40})\srefs/$type_re/(.*)$!) { |
|
874 |
+ if (defined $refs{$1}) { push @{$refs{$1}}, $2 } |
|
875 |
+ else { $refs{$1} = [$2] } |
|
876 |
+ } |
|
877 |
+ } |
|
878 |
+ close $fh or return; |
|
879 |
+ |
|
880 |
+ return \%refs; |
|
881 |
+} |
|
882 |
+ |
|
884 | 883 |
sub rep { |
885 | 884 |
my ($self, $user, $project) = @_; |
886 | 885 |
|
... | ... |
@@ -1587,21 +1586,23 @@ sub trees { |
1587 | 1586 |
return $trees; |
1588 | 1587 |
} |
1589 | 1588 |
|
1590 |
-sub cmd { |
|
1591 |
- my ($self, $user, $project, @cmd) = @_; |
|
1589 |
+sub _dec { |
|
1590 |
+ my ($self, $str) = @_; |
|
1592 | 1591 |
|
1593 |
- my $home = $self->rep_home; |
|
1592 |
+ my $enc = $self->encoding; |
|
1594 | 1593 |
|
1595 |
- my $rep = "$home/$user/$project.git"; |
|
1594 |
+ my $new_str; |
|
1595 |
+ eval { $new_str = decode($enc, $str) }; |
|
1596 | 1596 |
|
1597 |
- # Execute git command |
|
1598 |
- return $self->cmd_rep($rep, @cmd); |
|
1597 |
+ return $@ ? $str : $new_str; |
|
1599 | 1598 |
} |
1600 | 1599 |
|
1601 |
-sub cmd_rep { |
|
1602 |
- my ($self, $rep, @cmd) = @_; |
|
1600 |
+sub _enc { |
|
1601 |
+ my ($self, $str) = @_; |
|
1603 | 1602 |
|
1604 |
- return ($self->bin, "--git-dir=$rep", @cmd); |
|
1603 |
+ my $enc = $self->encoding; |
|
1604 |
+ |
|
1605 |
+ return encode($enc, $str); |
|
1605 | 1606 |
} |
1606 | 1607 |
|
1607 | 1608 |
sub _mode_str { |