File Coverage

blib/lib/Git/Repository.pm
Criterion Covered Total %
statement 126 130 96.9
branch 64 64 100.0
condition 20 28 71.4
subroutine 25 27 92.5
pod 4 7 57.1
total 239 256 93.3


line stmt bran cond sub pod time code
1             package Git::Repository;
2             $Git::Repository::VERSION = '1.326';
3 18     18   448141 use warnings;
  18         32  
  18         1058  
4 18     18   112 use strict;
  18         50  
  18         535  
5 18     18   497 use 5.006;
  18         74  
6              
7 18     18   130 use Carp;
  18         64  
  18         1844  
8 18     18   110 use File::Spec;
  18         34  
  18         626  
9 18     18   80 use Cwd qw( cwd realpath );
  18         34  
  18         1175  
10              
11 18     18   9936 use Git::Repository::Command;
  18         62  
  18         233  
12 18     18   3803 use Git::Version::Compare qw( :ops );
  18         8223  
  18         4858  
13              
14             # helper function
15             sub _abs_path {
16             my ( $path, $base ) = @_;
17             my $abs_path = File::Spec->rel2abs( $path, $base );
18              
19             # normalize, but don't die on Win32 if the path doesn't exist
20             eval { $abs_path = realpath($abs_path); };
21             return $abs_path;
22             }
23              
24 18     18   26776 use namespace::clean;
  18         355087  
  18         153  
25              
26             # a few simple accessors
27             for my $attr (qw( git_dir work_tree options )) {
28 18     18   7245 no strict 'refs';
  18         40  
  18         22776  
29 508 100   508   19332 *$attr = sub { return ref $_[0] ? $_[0]{$attr} : () };
30             }
31              
32             # backward compatible aliases
33             sub repo_path {
34 0     0 0 0 croak "repo_path() is obsolete, please use git_dir() instead";
35             }
36             sub wc_path {
37 0     0 0 0 croak "wc_path() is obsolete, please use work_tree() instead";
38             }
39              
40             #
41             # support for loading plugins
42             #
43             sub import {
44 34     34   6060 my ( $class, @plugins ) = @_;
45              
46 34         715259 for my $plugin (@plugins) {
47 5 100       26 ( $plugin, my @names ) = @$plugin if ref $plugin;
48 5 100       19 $plugin
49             = substr( $plugin, 0, 1 ) eq '+'
50             ? substr( $plugin, 1 )
51             : "Git::Repository::Plugin::$plugin";
52 5 100   1   428 eval "use $plugin; 1;" or croak $@;
  1     1   539  
  1     1   147  
  1     1   18  
  1     1   410  
  0         0  
  0         0  
  1         355  
  1         401  
  1         19  
  1         4  
  1         2  
  1         10  
  1         323  
  1         178  
  1         14  
53 4         20 $plugin->install(@names);
54             }
55             }
56              
57             #
58             # constructor-related methods
59             #
60              
61             sub new {
62 55     55 1 109735 my ( $class, @arg ) = @_;
63              
64             # create the object
65 55         356 my $self = bless {}, $class;
66              
67             # take out the option hash
68 55         210 my ( $options, %arg );
69             {
70 55         186 my @o;
  55         180  
71 55 100       634 %arg = grep !( ref eq 'HASH' ? push @o, $_ : 0 ), @arg;
72 55 100       577 croak "Too many option hashes given: @o" if @o > 1;
73 54   100     661 $options = $self->{options} = shift @o || {};
74             }
75              
76             # ignore 'input' and 'fatal' options during object creation
77 54         171 my $input = delete $options->{input};
78 54         204 my $fatal = delete $options->{fatal};
79              
80             # die if deprecated parameters are given
81             croak "repository is obsolete, please use git_dir instead"
82 54 100       2577 if defined delete $arg{repository};
83             croak "working_copy is obsolete, please use work_tree instead"
84 50 100       823 if defined delete $arg{working_copy};
85              
86             # setup default options
87 48         152 my $git_dir = delete $arg{git_dir};
88 48         130 my $work_tree = delete $arg{work_tree};
89              
90 48 100       212 croak "Unknown parameters: @{[keys %arg]}" if keys %arg;
  1         161  
91              
92             # compute the various paths
93 47 100       307278 my $cwd = defined $options->{cwd} ? $options->{cwd} : cwd();
94              
95             # if work_tree or git_dir are relative, they are relative to cwd
96 47 100 66     1119 -d ( $git_dir = _abs_path( $git_dir, $cwd ) )
97             or croak "directory not found: $git_dir"
98             if defined $git_dir;
99 46 100 66     570 -d ( $work_tree = _abs_path( $work_tree, $cwd ) )
100             or croak "directory not found: $work_tree"
101             if defined $work_tree;
102              
103             # if no cwd option given, assume we want to work in work_tree
104             $cwd = defined $options->{cwd} ? $options->{cwd}
105 45 100       152973 : defined $work_tree ? $work_tree
    100          
106             : cwd();
107              
108             # we'll always have to compute it if not defined
109 45 100       1308 $self->{git_dir} = _abs_path(
110             Git::Repository->run(
111             qw( rev-parse --git-dir ),
112             { %$options, cwd => $cwd }
113             ),
114             $cwd
115             ) if !defined $git_dir;
116              
117             # there are 4 possible cases
118 43 100       447 if ( !defined $work_tree ) {
119              
120             # 1) no path defined: trust git with the values
121             # $self->{git_dir} already computed
122              
123             # 2) only git_dir was given: trust it
124 29 100       575 $self->{git_dir} = $git_dir if defined $git_dir;
125              
126             # in a non-bare repository, the work tree is just above the gitdir
127 29 100       441 if ( $self->run(qw( config --bool core.bare )) ne 'true' ) {
128             $self->{work_tree}
129 23         2051 = _abs_path( File::Spec->updir, $self->{git_dir} );
130             }
131             }
132             else {
133              
134             # 3) only work_tree defined:
135 14 100       107 if ( !defined $git_dir ) {
136              
137             # $self->{git_dir} already computed
138              
139             # check work_tree is the top-level work tree, and not a subdir
140 12         184 my $cdup = Git::Repository->run( qw( rev-parse --show-cdup ),
141             { %$options, cwd => $cwd } );
142             $self->{work_tree}
143 12 100       802 = $cdup ? _abs_path( $cdup, $work_tree ) : $work_tree;
144             }
145              
146             # 4) both path defined: trust the values
147             else {
148 2         440 $self->{git_dir} = $git_dir;
149 2         25 $self->{work_tree} = $work_tree;
150             }
151             }
152              
153             # sanity check
154             my $gitdir
155 43   100     508 = eval { _abs_path( $self->run(qw( rev-parse --git-dir )), $cwd ) }
156             || '';
157             croak "fatal: not a git repository: $self->{git_dir}"
158 43 100       674 if $self->{git_dir} ne $gitdir;
159              
160             # put back the ignored options
161 41 100       286 $options->{input} = $input if defined $input;
162 41 100       169 $options->{fatal} = $fatal if defined $fatal;
163              
164 41         1525 return $self;
165             }
166              
167             # create() is now fully deprecated
168             sub create {
169 1     1 0 8600 croak "create() is deprecated, see Git::Repository::Tutorial for better alternatives";
170             }
171              
172             #
173             # command-related methods
174             #
175              
176             # return a Git::Repository::Command object
177             sub command {
178 4 100   4 1 4704 shift @_ if !ref $_[0]; # remove class name if called as class method
179 4         36 return Git::Repository::Command->new(@_);
180             }
181              
182             # run a command, returns the output
183             # die with errput if any
184             sub run {
185 351     351 1 510630 my ( $self, @cmd ) = @_;
186              
187             # split the args to get the optional callbacks
188 351         1037 my @cb;
189 351 100       1625 @cmd = grep { ref eq 'CODE' ? !push @cb, $_ : 1 } @cmd;
  809         5546  
190              
191 351         1396 local $Carp::CarpLevel = 1;
192              
193             # run the command (pass the instance if called as an instance method)
194 351 100       7334 my $command
195             = Git::Repository::Command->new( ref $self ? $self : (), @cmd );
196              
197             # return the output or die
198 342         5368583 return $command->final_output(@cb);
199             }
200              
201             #
202             # version comparison methods
203             #
204              
205             # NOTE: it doesn't make sense to try to cache the results of version():
206             # - yes, it will make faster benchmarks, but
207             # - the 'git' option allows to change the git binary anytime
208             # - version comparison is usually done once anyway
209             sub version {
210             return (
211 129     129 1 1294467 shift->run( '--version', grep { ref eq 'HASH' } @_ )
  54         420  
212             =~ /git version (.*)/g )[0];
213             }
214              
215             BEGIN {
216 18     18   143 for my $op ( qw( lt gt le ge eq ne ) ) {
217 18     18   300 no strict 'refs';
  18         112  
  18         1859  
218 108 100 66 50   16017 *{"version_$op"} = eval << "OP";
  108 100 66     1550  
  50 100 66     40657  
  50 100 66     130  
  50 100 66     414  
  50 100 66     253  
  46         418336  
  46         141  
  46         540  
  46         338  
  50         530615  
  50         133  
  50         405  
  50         268  
  47         35769  
  47         115  
  47         418  
  47         747  
  32         352217  
  32         113  
  32         347  
  32         224  
  47         34541  
  47         134  
  47         387  
  47         211  
219             sub {
220             my \$r = shift;
221             my \@o;
222             my (\$v) = grep !( ref && ref eq 'HASH' ? push \@o, \$_ : 0 ), \@_;
223             return ${op}_git( \$r->version(\@o), \$v );
224             }
225             OP
226             }
227             }
228              
229             1;
230              
231             __END__