File Coverage

blib/lib/Git/Repository/Log/Iterator.pm
Criterion Covered Total %
statement 59 65 90.7
branch 14 18 77.7
condition 7 8 87.5
subroutine 10 12 83.3
pod 4 4 100.0
total 94 107 87.8


line stmt bran cond sub pod time code
1             package Git::Repository::Log::Iterator;
2             $Git::Repository::Log::Iterator::VERSION = '1.312';
3 2     2   9 use strict;
  2         4  
  2         66  
4 2     2   9 use warnings;
  2         3  
  2         51  
5 2     2   29 use 5.006;
  2         6  
  2         60  
6 2     2   10 use Carp;
  2         3  
  2         128  
7 2     2   12 use Scalar::Util qw( blessed );
  2         3  
  2         138  
8              
9 2     2   8 use Git::Repository;
  2         4  
  2         22  
10 2     2   40 use Git::Repository::Command;
  2         7  
  2         24  
11 2     2   1209 use Git::Repository::Log;
  2         4  
  2         1250  
12              
13             sub new {
14 13     13 1 88 my ( $class, @cmd ) = @_;
15              
16             # pick up unsupported log options
17 13         31 my @badopts = do {
18 13         27 my $options = 1;
19 23 100       99 grep {/^--(?:pretty=(?!raw).*|graph)$/}
  25         241  
20 13         48 grep { $options = 0 if $_ eq '--'; $options } @cmd;
  25         134  
21             };
22 13 100       536 croak "log() cannot parse @badopts. "
23             . 'Use run( log => ... ) to parse the output yourself'
24             if @badopts;
25              
26             # note: there is no --color option to git log before 1.5.3.3
27 11   66     237 my ($r) = grep blessed $_ && $_->isa('Git::Repository'), @cmd;
28 11   100     106 $r ||= 'Git::Repository'; # no Git::Repository object given
29 11 50       159 unshift @cmd, '--no-color' if $r->version_ge('1.5.3.3');
30              
31             # enforce the format
32 11         372350 @cmd = ( 'log', '--pretty=raw', @cmd );
33              
34             # run the command (@cmd may hold a Git::Repository instance)
35 11         227 my $cmd = Git::Repository::Command->new(@cmd);
36 11         590811 bless { cmd => $cmd, fh => $cmd->stdout }, $class;
37             }
38              
39             sub new_from_fh {
40 0     0 1 0 my ( $class, $fh ) = @_;
41 0         0 bless { fh => $fh }, $class;
42             }
43              
44             sub new_from_file {
45 0     0 1 0 my ( $class, $file ) = @_;
46 0 0       0 open my $fh, '<', $file or die "Can't open $file: $!";
47 0         0 bless { fh => $fh }, $class;
48             }
49              
50             sub next {
51 41     41 1 10294 my ($self) = @_;
52 41         117 my $fh = $self->{fh};
53              
54             # get records
55 41 100       286 my @records = defined $self->{record} ? ( delete $self->{record} ) : ();
56             {
57 41         206 local $/ = "\n\n";
  41         203  
58 41         95483 while (<$fh>) {
59 63 100 100     719 $self->{record} = $_, last if /\Acommit / && @records;
60 40         899 push @records, $_;
61             }
62             }
63              
64             # EOF
65 41 100       173 if ( !@records ) {
66 10 50       45 if ( $self->{cmd} ) { # might catch some git errors
67 10         139 $self->{cmd}->final_output();
68             }
69             else { # just close the filehandle
70 0         0 $self->{fh}->close;
71             }
72 8         2717 return;
73             }
74              
75             # the first two records are always the same, with --pretty=raw
76 31         219 local $/ = "\n";
77 31         181 my ( $header, $message, $extra ) = ( @records, '', '' );
78 31         111 chomp $header;
79 31         431 my @headers = map { chomp; split / /, $_, 2 } split /^(?=\S)/m, $header;
  168         236  
  168         784  
80 31         529 s/\n /\n/g for @headers;
81 31 100       168 chomp( $message, $extra ) if exists $self->{record};
82              
83             # create the log object
84 31         317 return Git::Repository::Log->new(
85             @headers,
86             message => $message,
87             extra => $extra,
88             );
89             }
90              
91             1;
92              
93             # ABSTRACT: Split a git log stream into records
94              
95              
96             __END__
97             =pod
98              
99             =head1 NAME
100              
101             Git::Repository::Log::Iterator - Split a git log stream into records
102              
103             =head1 VERSION
104              
105             version 1.312
106              
107             =head1 SYNOPSIS
108              
109             use Git::Repository::Log::Iterator;
110              
111             # use a default Git::Repository context
112             my $iter = Git::Repository::Log::Iterator->new('HEAD~10..');
113              
114             # or provide an existing instance
115             my $iter = Git::Repository::Log::Iterator->new( $r, 'HEAD~10..' );
116              
117             # get the next log record
118             while ( my $log = $iter->next ) {
119             ...;
120             }
121              
122             =head1 DESCRIPTION
123              
124             L<Git::Repository::Log::Iterator> initiates a B<git log> command
125             from a list of paramaters and parses its output to produce
126             L<Git::Repository::Log> objects represening each log item.
127              
128             =head1 METHODS
129              
130             =head2 new
131              
132             my $iter = Git::Repository::Log::Iterator->new( @args );
133              
134             Create a new B<git log> stream from the parameter list in C<@args>
135             and return a iterator on it.
136              
137             C<new()> will happily accept any parameters, but note that
138             L<Git::Repository::Log::Iterator> expects the output to look like that
139             of C<--pretty=raw>, and so will force the the C<--pretty> option
140             (in case C<format.pretty> is defined in the Git configuration).
141             It will also forcibly remove colored output (using C<--color=never>).
142              
143             Extra output (like patches) will be stored in the C<extra> parameter of
144             the L<Git::Repository::Log> object. Decorations will be lost.
145              
146             When unsupported options are recognized in the parameter list, C<new()>
147             will C<croak()> with a message advising to use C<< run( 'log' => ... ) >>
148             to parse the output yourself.
149              
150             The object is really a blessed hash reference, with only two keys:
151              
152             =over 4
153              
154             =item cmd
155              
156             The L<Git::Repository::Command> object running the actual B<git log>
157             command. It might not be defined in some cases (see below L</new_from_fh>
158             and L</new_from_file>).
159              
160             =item fh
161              
162             The filehandle from which the output of B<git log> is actually read.
163             This is the only attribute needed to run the L</next> method.
164              
165             =back
166              
167             =head2 new_from_fh
168              
169             This constructor makes it possible to provide the filehandle directly.
170              
171             The C<cmd> key is not defined when using this constructor.
172              
173             =head2 new_from_file
174              
175             This constructor makes it possible to provide a filename that will be
176             C<open()>ed to produce a filehandle to read the log stream from.
177              
178             The C<cmd> key is not defined when using this constructor.
179              
180             =head2 next
181              
182             my $log = $iter->next;
183              
184             Return the next log item as a L<Git::Repository::Log> object,
185             or nothing if the stream has ended.
186              
187             =head1 BUGS
188              
189             Please report any bugs or feature requests on the bugtracker website
190             http://rt.cpan.org/NoAuth/Bugs.html?Dist=Git-Repository-Plugin-Log or by
191             email to bug-git-repository-plugin-log@rt.cpan.org.
192              
193             When submitting a bug or request, please include a test-file or a
194             patch to an existing test-file that illustrates the bug or desired
195             feature.
196              
197             =head1 AUTHOR
198              
199             Philippe Bruhat (BooK) <book@cpan.org>
200              
201             =head1 COPYRIGHT
202              
203             Copyright 2010-2013 Philippe Bruhat (BooK), all rights reserved.
204              
205             =head1 LICENSE
206              
207             This program is free software; you can redistribute it and/or modify it
208             under the same terms as Perl itself.
209              
210             =cut
211