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.325';
3 16     16   154113 use warnings;
  16         75  
  16         657  
4 16     16   105 use strict;
  16         37  
  16         607  
5 16     16   432 use 5.006;
  16         82  
6              
7 16     16   101 use Carp;
  16         46  
  16         2100  
8 16     16   111 use File::Spec;
  16         35  
  16         642  
9 16     16   114 use Cwd qw( cwd realpath );
  16         36  
  16         1351  
10              
11 16     16   8729 use Git::Repository::Command;
  16         48  
  16         185  
12 16     16   2035 use Git::Version::Compare qw( :ops );
  16         3383  
  16         4784  
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   10223 use namespace::clean;
  16         277460  
  16         116  
25              
26             # a few simple accessors
27             for my $attr (qw( git_dir work_tree options )) {
28 16     16   5801 no strict 'refs';
  16         41  
  16         18182  
29 508 100   508   15925 *$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   5762 my ( $class, @plugins ) = @_;
45              
46 33         19022 for my $plugin (@plugins) {
47 5 100       26 ( $plugin, my @names ) = @$plugin if ref $plugin;
48 5 100       26 $plugin
49             = substr( $plugin, 0, 1 ) eq '+'
50             ? substr( $plugin, 1 )
51             : "Git::Repository::Plugin::$plugin";
52 5 100   1   418 eval "use $plugin; 1;" or croak $@;
  1     1   656  
  1     1   198  
  1     1   29  
  1     1   618  
  0         0  
  0         0  
  1         447  
  1         235  
  1         20  
  1         9  
  1         2  
  1         13  
  1         427  
  1         214  
  1         27  
53 4         30 $plugin->install(@names);
54             }
55             }
56              
57             #
58             # constructor-related methods
59             #
60              
61             sub new {
62 55     55 1 22521 my ( $class, @arg ) = @_;
63              
64             # create the object
65 55         474 my $self = bless {}, $class;
66              
67             # take out the option hash
68 55         246 my ( $options, %arg );
69             {
70 55         156 my @o;
  55         147  
71 55 100       759 %arg = grep !( ref eq 'HASH' ? push @o, $_ : 0 ), @arg;
72 55 100       884 croak "Too many option hashes given: @o" if @o > 1;
73 54   100     989 $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         191 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       785 if defined delete $arg{repository};
83             croak "working_copy is obsolete, please use work_tree instead"
84 50 100       881 if defined delete $arg{working_copy};
85              
86             # setup default options
87 48         156 my $git_dir = delete $arg{git_dir};
88 48         135 my $work_tree = delete $arg{work_tree};
89              
90 48 100       292 croak "Unknown parameters: @{[keys %arg]}" if keys %arg;
  1         117  
91              
92             # compute the various paths
93 47 100       151647 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     1545 -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     790 -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       106534 : defined $work_tree ? $work_tree
    100          
106             : cwd();
107              
108             # we'll always have to compute it if not defined
109 45 100       1856 $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       414 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       501 $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       588 if ( $self->run(qw( config --bool core.bare )) ne 'true' ) {
128             $self->{work_tree}
129 23         2764 = _abs_path( File::Spec->updir, $self->{git_dir} );
130             }
131             }
132             else {
133              
134             # 3) only work_tree defined:
135 14 100       126 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         168 my $cdup = Git::Repository->run( qw( rev-parse --show-cdup ),
141             { %$options, cwd => $cwd } );
142             $self->{work_tree}
143 12 100       1134 = $cdup ? _abs_path( $cdup, $work_tree ) : $work_tree;
144             }
145              
146             # 4) both path defined: trust the values
147             else {
148 2         42 $self->{git_dir} = $git_dir;
149 2         29 $self->{work_tree} = $work_tree;
150             }
151             }
152              
153             # sanity check
154             my $gitdir
155 43   100     617 = 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       869 if $self->{git_dir} ne $gitdir;
159              
160             # put back the ignored options
161 41 100       214 $options->{input} = $input if defined $input;
162 41 100       230 $options->{fatal} = $fatal if defined $fatal;
163              
164 41         2366 return $self;
165             }
166              
167             # create() is now fully deprecated
168             sub create {
169 1     1 0 6540 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 3793 shift @_ if !ref $_[0]; # remove class name if called as class method
179 4         42 return Git::Repository::Command->new(@_);
180             }
181              
182             # run a command, returns the output
183             # die with errput if any
184             sub run {
185 355     355 1 108747 my ( $self, @cmd ) = @_;
186              
187             # split the args to get the optional callbacks
188 355         1167 my @cb;
189 355 100       1453 @cmd = grep { ref eq 'CODE' ? !push @cb, $_ : 1 } @cmd;
  808         4252  
190              
191 355         1738 local $Carp::CarpLevel = 1;
192              
193             # run the command (pass the instance if called as an instance method)
194 355 100       5026 my $command
195             = Git::Repository::Command->new( ref $self ? $self : (), @cmd );
196              
197             # return the output or die
198 346         2840133 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 133     133 1 31230 shift->run( '--version', grep { ref eq 'HASH' } @_ )
  54         555  
212             =~ /git version (.*)/g )[0];
213             }
214              
215             BEGIN {
216 16     16   80 for my $op ( qw( lt gt le ge eq ne ) ) {
217 16     16   186 no strict 'refs';
  16         37  
  16         1264  
218 96 100 66 55   12786 *{"version_$op"} = eval << "OP";
  96 100 66     1227  
  55 100 66     44811  
  55 100 66     142  
  55 100 66     584  
  55 100 66     297  
  32         28196  
  32         97  
  32         355  
  32         214  
  37         33686  
  37         98  
  37         534  
  37         293  
  53         65182  
  53         164  
  53         639  
  53         368  
  51         30179  
  51         111  
  51         448  
  51         244  
  48         30413  
  48         122  
  48         425  
  48         279  
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__