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.324';
3 16     16   109288 use warnings;
  16         49  
  16         457  
4 16     16   96 use strict;
  16         28  
  16         339  
5 16     16   371 use 5.006;
  16         67  
6              
7 16     16   93 use Carp;
  16         32  
  16         1633  
8 16     16   106 use File::Spec;
  16         34  
  16         568  
9 16     16   89 use Cwd qw( cwd realpath );
  16         35  
  16         1127  
10              
11 16     16   6924 use Git::Repository::Command;
  16         43  
  16         161  
12 16     16   1584 use Git::Version::Compare qw( :ops );
  16         2821  
  16         3378  
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   7584 use namespace::clean;
  16         225527  
  16         91  
25              
26             # a few simple accessors
27             for my $attr (qw( git_dir work_tree options )) {
28 16     16   4955 no strict 'refs';
  16         30  
  16         16137  
29 508 100   508   14595 *$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   5310 my ( $class, @plugins ) = @_;
45              
46 33         15685 for my $plugin (@plugins) {
47 5 100       28 ( $plugin, my @names ) = @$plugin if ref $plugin;
48 5 100       25 $plugin
49             = substr( $plugin, 0, 1 ) eq '+'
50             ? substr( $plugin, 1 )
51             : "Git::Repository::Plugin::$plugin";
52 5 100   1   376 eval "use $plugin; 1;" or croak $@;
  1     1   666  
  1     1   190  
  1     1   17  
  1     1   503  
  0         0  
  0         0  
  1         389  
  1         247  
  1         19  
  1         7  
  1         2  
  1         20  
  1         484  
  1         195  
  1         18  
53 4         28 $plugin->install(@names);
54             }
55             }
56              
57             #
58             # constructor-related methods
59             #
60              
61             sub new {
62 55     55 1 18702 my ( $class, @arg ) = @_;
63              
64             # create the object
65 55         387 my $self = bless {}, $class;
66              
67             # take out the option hash
68 55         203 my ( $options, %arg );
69             {
70 55         117 my @o;
  55         128  
71 55 100       757 %arg = grep !( ref eq 'HASH' ? push @o, $_ : 0 ), @arg;
72 55 100       605 croak "Too many option hashes given: @o" if @o > 1;
73 54   100     571 $options = $self->{options} = shift @o || {};
74             }
75              
76             # ignore 'input' and 'fatal' options during object creation
77 54         194 my $input = delete $options->{input};
78 54         158 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       587 if defined delete $arg{repository};
83             croak "working_copy is obsolete, please use work_tree instead"
84 50 100       531 if defined delete $arg{working_copy};
85              
86             # setup default options
87 48         102 my $git_dir = delete $arg{git_dir};
88 48         185 my $work_tree = delete $arg{work_tree};
89              
90 48 100       225 croak "Unknown parameters: @{[keys %arg]}" if keys %arg;
  1         105  
91              
92             # compute the various paths
93 47 100       108162 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     1254 -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     603 -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       65048 : defined $work_tree ? $work_tree
    100          
106             : cwd();
107              
108             # we'll always have to compute it if not defined
109 45 100       1079 $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       380 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       412 $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       479 if ( $self->run(qw( config --bool core.bare )) ne 'true' ) {
128             $self->{work_tree}
129 23         1796 = _abs_path( File::Spec->updir, $self->{git_dir} );
130             }
131             }
132             else {
133              
134             # 3) only work_tree defined:
135 14 100       128 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         135 my $cdup = Git::Repository->run( qw( rev-parse --show-cdup ),
141             { %$options, cwd => $cwd } );
142             $self->{work_tree}
143 12 100       501 = $cdup ? _abs_path( $cdup, $work_tree ) : $work_tree;
144             }
145              
146             # 4) both path defined: trust the values
147             else {
148 2         46 $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     304 = 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       724 if $self->{git_dir} ne $gitdir;
159              
160             # put back the ignored options
161 41 100       173 $options->{input} = $input if defined $input;
162 41 100       238 $options->{fatal} = $fatal if defined $fatal;
163              
164 41         1611 return $self;
165             }
166              
167             # create() is now fully deprecated
168             sub create {
169 1     1 0 4249 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 2806 shift @_ if !ref $_[0]; # remove class name if called as class method
179 4         26 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 103032 my ( $self, @cmd ) = @_;
186              
187             # split the args to get the optional callbacks
188 346         981 my @cb;
189 346 100       1011 @cmd = grep { ref eq 'CODE' ? !push @cb, $_ : 1 } @cmd;
  778         2597  
190              
191 346         1321 local $Carp::CarpLevel = 1;
192              
193             # run the command (pass the instance if called as an instance method)
194 346 100       3627 my $command
195             = Git::Repository::Command->new( ref $self ? $self : (), @cmd );
196              
197             # return the output or die
198 337         2076280 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 28135 shift->run( '--version', grep { ref eq 'HASH' } @_ )
  54         514  
212             =~ /git version (.*)/g )[0];
213             }
214              
215             BEGIN {
216 16     16   62 for my $op ( qw( lt gt le ge eq ne ) ) {
217 16     16   122 no strict 'refs';
  16         30  
  16         1091  
218 96 100 66 53   10853 *{"version_$op"} = eval << "OP";
  96 100 66     1011  
  53 100 66     25368  
  53 100 66     117  
  53 100 66     657  
  53 100 66     233  
  36         21257  
  36         72  
  36         309  
  36         158  
  39         24339  
  39         83  
  39         357  
  39         190  
  45         23659  
  45         89  
  45         302  
  45         160  
  48         21281  
  48         97  
  48         339  
  48         154  
  46         21321  
  46         84  
  46         282  
  46         165  
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__