File Coverage

blib/lib/App/Rgit/Repository.pm
Criterion Covered Total %
statement 85 99 85.8
branch 29 42 69.0
condition 11 18 61.1
subroutine 16 16 100.0
pod 8 8 100.0
total 149 183 81.4


line stmt bran cond sub pod time code
1             package App::Rgit::Repository;
2              
3 5     5   26 use strict;
  5         8  
  5         178  
4 5     5   24 use warnings;
  5         8  
  5         102  
5              
6 5     5   21 use Cwd (); # cwd
  5         8  
  5         71  
7 5     5   21 use File::Spec (); # canonpath, catdir, splitdir, abs2rel
  5         8  
  5         85  
8 5     5   4844 use POSIX (); # WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG SIGINT SIGQUIT
  5         38528  
  5         128  
9              
10 5     5   575 use App::Rgit::Utils (); # abs_path
  5         9  
  5         955  
11              
12             my ($WIFEXITED, $WEXITSTATUS, $WIFSIGNALED, $WTERMSIG);
13              
14             BEGIN {
15 5         19 $WIFEXITED = eval { POSIX::WIFEXITED(0); 1 } ? \&POSIX::WIFEXITED
  5         32  
16 5 50   5   10 : sub { 1 };
  0         0  
17 5         11 $WEXITSTATUS = eval { POSIX::WEXITSTATUS(0); 1 } ? \&POSIX::WEXITSTATUS
  5         16  
18 5 50       10 : sub { shift() >> 8 };
  0         0  
19 5         13 $WIFSIGNALED = eval { POSIX::WIFSIGNALED(0); 1 } ? \&POSIX::WIFSIGNALED
  5         14  
20 5 50       22 : sub { shift() & 127 };
  0         0  
21 5         12 $WTERMSIG = eval { POSIX::WTERMSIG(0); 1 } ? \&POSIX::WTERMSIG
  5         7152  
22 5 50       30 : sub { shift() & 127 };
  0         0  
23             }
24              
25             =head1 NAME
26              
27             App::Rgit::Repository - Class representing a Git repository.
28              
29             =head1 VERSION
30              
31             Version 0.08
32              
33             =cut
34              
35             our $VERSION = '0.08';
36              
37             =head1 DESCRIPTION
38              
39             Class representing a Git repository.
40              
41             This is an internal class to L.
42              
43             =head1 METHODS
44              
45             =head2 C<< new dir => $dir [, fake => 1 ] >>
46              
47             Creates a new repository starting from C<$dir>.
48             If the C option is passed, C<$dir> isn't checked to be a valid C repository.
49              
50             =cut
51              
52             sub new {
53 90     90 1 17096 my $class = shift;
54 90   33     677 $class = ref $class || $class;
55              
56 90         347 my %args = @_;
57              
58 90         222 my $dir = $args{dir};
59 90 100       228 if (defined $dir) {
60 67         232 $dir = App::Rgit::Utils::abs_path($dir);
61             } else {
62 23         151367 $dir = Cwd::cwd;
63             }
64 90         976 $dir = File::Spec->canonpath($dir);
65              
66 90         246 my ($repo, $bare, $name, $work);
67 90 100       668 if ($args{fake}) {
68 23         119 $repo = $work = $dir;
69             } else {
70 67 100 66     12676 return unless -d $dir
      100        
      100        
71             and -d "$dir/refs"
72             and -d "$dir/objects"
73             and -e "$dir/HEAD";
74              
75 12         75 my @chunks = File::Spec->splitdir($dir);
76 12         28 my $last = pop @chunks;
77 12 50       28 return unless defined $last;
78              
79 12 100 66     110 if (@chunks and $last eq '.git') {
    50          
80 8         11 $bare = 0;
81 8         15 $name = $chunks[-1];
82 8         56 $work = File::Spec->catdir(@chunks);
83             } elsif ($last =~ /(.+)\.git$/) {
84 4         10 $bare = 1;
85 4         9 $name = $1;
86 4         34 $work = File::Spec->catdir(@chunks, $last);
87             } else {
88 0         0 return;
89             }
90              
91 12         33 $repo = $dir;
92             }
93              
94 35         1869 bless {
95             fake => !!$args{fake},
96             repo => $repo,
97             bare => $bare,
98             name => $name,
99             work => $work,
100             }, $class;
101             }
102              
103             =head2 C
104              
105             C into the repository's directory.
106              
107             =cut
108              
109             sub chdir {
110 17     17 1 52 my $self = shift;
111 17         807 my $dir = $self->work;
112 17 50       955 chdir $dir or do {
113 0         0 warn "Couldn't chdir into $dir: $!";
114 0         0 return;
115             };
116 17         1415 return 1;
117             }
118              
119             =head2 C
120              
121             Runs C on the repository for the L configuration C<$conf>.
122             When the repository isn't fake, the format substitutions applies to C<@args> elements.
123             Returns the exit code.
124              
125             =cut
126              
127             my $abs2rel = sub {
128             my $a = File::Spec->abs2rel(@_);
129             $a = $_[0] unless defined $a;
130             $a;
131             };
132              
133             my %escapes = (
134             '%' => sub { '%' },
135             'n' => sub { shift->name },
136             'g' => sub { $abs2rel->(shift->repo, shift->root) },
137             'G' => sub { shift->repo },
138             'w' => sub { $abs2rel->(shift->work, shift->root) },
139             'W' => sub { shift->work },
140             'b' => sub {
141             my ($self, $conf) = @_;
142             $abs2rel->(
143             $self->bare ? $self->repo : $self->work . '.git',
144             $conf->root
145             );
146             },
147             'B' => sub { $_[0]->bare ? $_[0]->repo : $_[0]->work . '.git' },
148             'R' => sub { $_[1]->root },
149             );
150             my $e = quotemeta join '', keys %escapes;
151             $e = "[$e]";
152              
153             sub run {
154 18     18 1 39 my $self = shift;
155 18         29 my $conf = shift;
156 18 50       152 return unless $conf->isa('App::Rgit::Config');
157              
158 18         296 my @args = @_;
159              
160 18 100       636 unless ($self->fake) {
161 13         263 s/%($e)/$escapes{$1}->($self, $conf)/eg for @args;
  117         562  
162             }
163              
164 18         609 unshift @args, $conf->git;
165 18         735 $conf->info('Executing "', join(' ', @args), '" into ', $self->work, "\n");
166              
167             {
168 18 100       31 local $ENV{GIT_DIR} = $self->repo if exists $ENV{GIT_DIR};
  18         201  
169 18 100       174 local $ENV{GIT_EXEC_PATH} = $conf->git if exists $ENV{GIT_EXEC_PATH};
170 18         30 system { $args[0] } @args;
  18         221545  
171             }
172              
173 18 50       609 if ($? == -1) {
174 0         0 $conf->crit("Failed to execute git: $!\n");
175 0         0 return;
176             }
177              
178 18         60 my $ret;
179 18 50       570 $ret = $WEXITSTATUS->($?) if $WIFEXITED->($?);
180 18         38 my $sig;
181 18 50       248 if ($WIFSIGNALED->($?)) {
    100          
182 0         0 $sig = $WTERMSIG->($?);
183 0         0 $conf->warn("git died with signal $sig\n");
184 0 0 0     0 if ($sig == POSIX::SIGINT() || $sig == POSIX::SIGQUIT()) {
185 0         0 $conf->err("Aborting\n");
186 0         0 exit $sig;
187             }
188             } elsif ($ret) {
189 10         681 $conf->info("git returned $ret\n");
190             }
191              
192 18 100       1116 return wantarray ? ($ret, $sig) : $ret;
193             }
194              
195             =head2 C
196              
197             =head2 C
198              
199             =head2 C
200              
201             =head2 C
202              
203             =head2 C
204              
205             Read-only accessors.
206              
207             =cut
208              
209             BEGIN {
210 5     5 1 1180 eval "sub $_ { \$_[0]->{$_} }" for qw/fake repo bare name work/;
  26     26 1 736  
  18     18 1 121  
  13     13 1 142  
  85     85 1 1903  
  79     79   1052  
211             }
212              
213             =head1 SEE ALSO
214              
215             L.
216              
217             =head1 AUTHOR
218              
219             Vincent Pit, C<< >>, L.
220              
221             You can contact me by mail or on C (vincent).
222              
223             =head1 BUGS
224              
225             Please report any bugs or feature requests to C, or through the web interface at L.
226             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
227              
228             =head1 SUPPORT
229              
230             You can find documentation for this module with the perldoc command.
231              
232             perldoc App::Rgit::Repository
233              
234             =head1 COPYRIGHT & LICENSE
235              
236             Copyright 2008,2009,2010 Vincent Pit, all rights reserved.
237              
238             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
239              
240             =cut
241              
242             1; # End of App::Rgit::Repository