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.323';
3 16     16   132167 use warnings;
  16         68  
  16         528  
4 16     16   112 use strict;
  16         36  
  16         353  
5 16     16   436 use 5.006;
  16         62  
6              
7 16     16   98 use Carp;
  16         38  
  16         1733  
8 16     16   105 use File::Spec;
  16         35  
  16         582  
9 16     16   113 use Cwd qw( cwd realpath );
  16         32  
  16         1272  
10              
11 16     16   7795 use Git::Repository::Command;
  16         52  
  16         158  
12 16     16   1729 use Git::Version::Compare qw( :ops );
  16         3392  
  16         3763  
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 16     16   7993 use namespace::clean;
  16         251383  
  16         93  
25              
26             # a few simple accessors
27             for my $attr (qw( git_dir work_tree options )) {
28 16     16   5543 no strict 'refs';
  16         41  
  16         17399  
29 508 100   508   14747 *$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 33     33   5683 my ( $class, @plugins ) = @_;
45              
46 33         17121 for my $plugin (@plugins) {
47 5 100       25 ( $plugin, my @names ) = @$plugin if ref $plugin;
48 5 100       28 $plugin
49             = substr( $plugin, 0, 1 ) eq '+'
50             ? substr( $plugin, 1 )
51             : "Git::Repository::Plugin::$plugin";
52 5 100   1   384 eval "use $plugin; 1;" or croak $@;
  1     1   622  
  1     1   189  
  1     1   31  
  1     1   500  
  0         0  
  0         0  
  1         353  
  1         234  
  1         18  
  1         7  
  1         2  
  1         22  
  1         333  
  1         186  
  1         16  
53 4         29 $plugin->install(@names);
54             }
55             }
56              
57             #
58             # constructor-related methods
59             #
60              
61             sub new {
62 55     55 1 18136 my ( $class, @arg ) = @_;
63              
64             # create the object
65 55         437 my $self = bless {}, $class;
66              
67             # take out the option hash
68 55         293 my ( $options, %arg );
69             {
70 55         239 my @o;
  55         133  
71 55 100       784 %arg = grep !( ref eq 'HASH' ? push @o, $_ : 0 ), @arg;
72 55 100       833 croak "Too many option hashes given: @o" if @o > 1;
73 54   100     722 $options = $self->{options} = shift @o || {};
74             }
75              
76             # ignore 'input' and 'fatal' options during object creation
77 54         257 my $input = delete $options->{input};
78 54         243 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       664 if defined delete $arg{repository};
83             croak "working_copy is obsolete, please use work_tree instead"
84 50 100       616 if defined delete $arg{working_copy};
85              
86             # setup default options
87 48         128 my $git_dir = delete $arg{git_dir};
88 48         145 my $work_tree = delete $arg{work_tree};
89              
90 48 100       220 croak "Unknown parameters: @{[keys %arg]}" if keys %arg;
  1         102  
91              
92             # compute the various paths
93 47 100       124138 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     1921 -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     707 -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       71780 : defined $work_tree ? $work_tree
    100          
106             : cwd();
107              
108             # we'll always have to compute it if not defined
109 45 100       1316 $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       512 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       542 $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       511 if ( $self->run(qw( config --bool core.bare )) ne 'true' ) {
128             $self->{work_tree}
129 23         1874 = _abs_path( File::Spec->updir, $self->{git_dir} );
130             }
131             }
132             else {
133              
134             # 3) only work_tree defined:
135 14 100       122 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         187 my $cdup = Git::Repository->run( qw( rev-parse --show-cdup ),
141             { %$options, cwd => $cwd } );
142             $self->{work_tree}
143 12 100       656 = $cdup ? _abs_path( $cdup, $work_tree ) : $work_tree;
144             }
145              
146             # 4) both path defined: trust the values
147             else {
148 2         39 $self->{git_dir} = $git_dir;
149 2         26 $self->{work_tree} = $work_tree;
150             }
151             }
152              
153             # sanity check
154             my $gitdir
155 43   100     515 = 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       732 if $self->{git_dir} ne $gitdir;
159              
160             # put back the ignored option
161 41 100       219 $options->{input} = $input if defined $input;
162 41 100       231 $options->{fatal} = $fatal if defined $fatal;
163              
164 41         2092 return $self;
165             }
166              
167             # create() is now fully deprecated
168             sub create {
169 1     1 0 7233 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 2647 shift @_ if !ref $_[0]; # remove class name if called as class method
179 4         37 return Git::Repository::Command->new(@_);
180             }
181              
182             # run a command, returns the output
183             # die with errput if any
184             sub run {
185 346     346 1 112944 my ( $self, @cmd ) = @_;
186              
187             # split the args to get the optional callbacks
188 346         1031 my @cb;
189 346 100       1230 @cmd = grep { ref eq 'CODE' ? !push @cb, $_ : 1 } @cmd;
  778         3394  
190              
191 346         1514 local $Carp::CarpLevel = 1;
192              
193             # run the command (pass the instance if called as an instance method)
194 346 100       4015 my $command
195             = Git::Repository::Command->new( ref $self ? $self : (), @cmd );
196              
197             # return the output or die
198 337         2372889 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 124     124 1 28837 shift->run( '--version', grep { ref eq 'HASH' } @_ )
  54         519  
212             =~ /git version (.*)/g )[0];
213             }
214              
215             BEGIN {
216 16     16   70 for my $op ( qw( lt gt le ge eq ne ) ) {
217 16     16   142 no strict 'refs';
  16         33  
  16         1223  
218 96 100 66 57   12051 *{"version_$op"} = eval << "OP";
  96 100 66     1151  
  57 100 66     43934  
  57 100 66     167  
  57 100 66     586  
  57 100 66     287  
  55         27183  
  55         126  
  55         480  
  55         305  
  43         21737  
  43         99  
  43         345  
  43         172  
  35         22096  
  35         83  
  35         354  
  35         194  
  47         25051  
  47         109  
  47         387  
  47         195  
  30         20921  
  30         73  
  30         299  
  30         154  
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__