File Coverage

blib/lib/SVN/SVNLook.pm
Criterion Covered Total %
statement 9 107 8.4
branch 0 60 0.0
condition 0 6 0.0
subroutine 3 12 25.0
pod 6 7 85.7
total 18 192 9.3


line stmt bran cond sub pod time code
1             package SVN::SVNLook;
2 1     1   24900 use strict;
  1         3  
  1         39  
3 1     1   5 use warnings;
  1         3  
  1         32  
4 1     1   4 use Carp qw(cluck);
  1         6  
  1         2447  
5            
6             our $VERSION = 0.04;
7            
8             =head1 NAME
9            
10             SVN::SVNLook - Perl wrapper to the svnlook command.
11            
12             =head1 SYNOPSIS
13            
14             use SVN::SVNLook;
15            
16             my $revision = 1;
17             my $svnlook = SVN::SVNLook->new(repo => 'repo url',
18             cmd => 'path to svn look');
19             my ($author,$date,$logmessage) = $svnlook->info(revision => $revision);
20            
21             print "Author $author\n";
22             print "Date $date\n";
23             print "LogMessage $logmessage\n";
24            
25             =head1 DESCRIPTION
26            
27             SVN::SVNLook runs the command line client. This module was created to
28             make adding hooks script easier to manipulate.
29            
30             =cut
31            
32             =head1 METHODs
33            
34             =head2 youngest
35            
36             youngest ();
37            
38             Perform the youngest command on the repository.
39             Returns the revision number of the most recent revision as a scalar.
40            
41             =head2 info
42            
43             info (revision=>$revision);
44            
45             Perform the info command, for a given revision or transaction using
46             named parameters, or a single parameter will be assumed to mean
47             revision for backwards compatibility. The information returned is an
48             array containing author, date, and log message. If no $revision is
49             specified, info for the youngest revision is returned.
50            
51             =head2 author
52            
53             author (revision=>$revision);
54            
55             Perform the author command, for a given revision or transaction using
56             named parameters or a single parameter will be assumed to mean
57             revision for backwards compatibility. The information returned is the
58             author message. If no $revision or transaction is specified, author
59             for the youngest revision is returned.
60            
61             =head2 dirschanged
62            
63             dirschanged (revision=>$revision)
64            
65             Performs the dirs-changed command, for a given revision or transaction
66             using named parameters, or a single parameter will be assumed to mean
67             revision for backwards compatibility. This method returns a boolean and
68             an array reference.
69            
70             =head2 fileschanged
71            
72             fileschanged (revision=>$revision)
73            
74             Performs the changed command, for a given revision or transaction
75             using named parameters or a single parameter will be assumed to mean
76             revision for backwards compatibility this method returns 3 array
77             references added, deleted and modified.
78            
79             =head2 diff
80            
81             diff (revision=>$revision)
82            
83             Performs the diff command, for a given revision or transaction using
84             named parameters or a single parameter will be assumed to mean
85             revision for backwards compatability this method returns a hash
86             reference, with each file being the key and value being the diff info.
87            
88             =cut
89            
90            
91             sub new {
92 0     0 0   my $self = {};
93 0           my $class = shift;
94 0           %$self = @_;
95 0   0       $self->{repo} ||= $self->{target};
96 0 0         die "no repository specified" unless $self->{repo};
97 0           return bless $self, $class;
98             }
99            
100             sub youngest
101             {
102 0     0 1   my $self = shift;
103 0           my ($rev) = _read_from_process($self->{cmd}, 'youngest', $self->{repo});
104 0           return $rev;
105             }
106             sub info
107             {
108 0     0 1   my $self = shift;
109 0           my %args;
110 0 0         if ($#_ == 0)
111             {
112 0           $args{revision} = shift;
113             }
114             else
115             {
116 0           %args = @_;
117             }
118 0 0         my @svnlooklines = _read_from_process(
    0          
119             $self->{cmd},
120             'info',
121             $self->{repo},
122             ($args{revision} ? ('-r', $args{revision}) : ()),
123             ($args{transaction} ? ('-t', $args{transaction}) : ()),
124             );
125 0           my $author = shift @svnlooklines; # author of this change
126 0           my $date = shift @svnlooklines; # date of change
127 0           shift @svnlooklines; # log message size
128 0           my @log = map { "$_\n" } @svnlooklines;
  0            
129 0           my $logmessage = join('',@log);
130 0           return ($author,$date,$logmessage);
131             }
132             sub author
133             {
134 0     0 1   my $self = shift;
135 0           my %args;
136 0 0         if ($#_ == 0)
137             {
138 0           $args{revision} = shift;
139             }
140             else
141             {
142 0           %args = @_;
143             }
144 0 0         my @svnlooklines = _read_from_process(
    0          
145             $self->{cmd},
146             'author',
147             $self->{repo},
148             ($args{revision} ? ('-r', $args{revision}) : ()),
149             ($args{transaction} ? ('-t', $args{transaction}) : ()),
150             );
151 0           return $svnlooklines[0]; # author of this change
152             }
153            
154             sub dirschanged
155             {
156 0     0 1   my $self = shift;
157 0           my %args;
158 0 0         if ($#_ == 0)
159             {
160 0           $args{revision} = shift;
161             }
162             else
163             {
164 0           %args = @_;
165             }
166             # Figure out what directories have changed using svnlook.
167 0 0         my @dirschanged = _read_from_process(
    0          
168             $self->{cmd},
169             'dirs-changed',
170             $self->{repo},
171             ($args{revision} ? ('-r', $args{revision}) : ()),
172             ($args{transaction} ? ('-t', $args{transaction}) : ()),
173             );
174 0           my $rootchanged = 0;
175 0           for (my $i=0; $i<@dirschanged; ++$i)
176             {
177 0 0         if ($dirschanged[$i] eq '/')
178             {
179 0           $rootchanged = 1;
180             }
181             else
182             {
183 0           $dirschanged[$i] =~ s#^(.+)[/\\]$#$1#;
184             }
185             }
186 0           return ($rootchanged,\@dirschanged);
187             }
188            
189            
190             sub fileschanged
191             {
192 0     0 1   my $self = shift;
193 0           my %args;
194 0 0         if ($#_ == 0)
195             {
196 0           $args{revision} = shift;
197             }
198             else
199             {
200 0           %args = @_;
201             }
202            
203             # Figure out what files have changed using svnlook.
204 0 0         my @svnlooklines = _read_from_process(
    0          
205             $self->{cmd},
206             'changed',
207             $self->{repo},
208             ($args{revision} ? ('-r', $args{revision}) : ()),
209             ($args{transaction} ? ('-t', $args{transaction}) : ()),
210             );
211             # Parse the changed nodes.
212 0           my @adds;
213             my @dels;
214 0           my @mods;
215 0           foreach my $line (@svnlooklines)
216             {
217 0           my $path = '';
218 0           my $code = '';
219            
220             # Split the line up into the modification code and path, ignoring
221             # property modifications.
222 0 0         if ($line =~ /^(.). (.*)$/)
223             {
224 0           $code = $1;
225 0           $path = $2;
226             }
227 0 0         if ($code eq 'A')
    0          
228             {
229 0           push(@adds, $path);
230             }
231             elsif ($code eq 'D')
232             {
233 0           push(@dels, $path);
234             }
235             else
236             {
237 0           push(@mods, $path);
238             }
239             }
240 0           return (\@adds,\@dels,\@mods);
241             }
242            
243             sub diff
244             {
245 0     0 1   my $self = shift;
246 0           my %args;
247 0 0         if ($#_ == 0)
248             {
249 0           $args{revision} = shift;
250             }
251             else
252             {
253 0           %args = @_;
254             }
255            
256 0 0         my @difflines = _read_from_process(
    0          
257             $self->{cmd},
258             'diff',
259             $self->{repo},
260             ($args{revision} ? ('-r', $args{revision}) : ()),
261             ($args{transaction} ? ('-t', $args{transaction}) : ()),
262             ('--no-diff-deleted')
263             );
264             # Ok we need to split this out now , by file
265 0           my @lin = split(/Modified: (.*)\n=*\n/,join("\n",@difflines));
266 0           shift(@lin);
267 0           my %lines = @lin;
268 0           return %lines;
269             }
270             #
271             # PRIVATE METHODS
272             # Methods taken from commit-email.pl Copyright subversion team
273             #
274            
275             # NB. croak is not a defined subroutine - where did this come from?
276             # croak is defined in Carp, somehow didnt get included in CPAN post
277            
278             sub _read_from_process
279             {
280 0 0   0     unless (@_)
281             {
282 0           cluck("$0: read_from_process passed no arguments.\n");
283             }
284 0           my ($status, @output) = _safe_read_from_pipe(@_);
285 0 0         if ($status)
286             {
287 0           cluck("$0: `@_' failed with this output:", @output);
288             }
289             else
290             {
291 0           return @output;
292             }
293             }
294             sub _safe_read_from_pipe
295             {
296 0 0   0     unless (@_)
297             {
298 0           croak("$0: safe_read_from_pipe passed no arguments.\n");
299             }
300            
301 0           my $pid = open(SAFE_READ, '-|');
302 0 0         unless (defined $pid)
303             {
304 0           die "$0: cannot fork: $!\n";
305             }
306 0 0         unless ($pid)
307             {
308 0 0         open(STDERR, ">&STDOUT") or die "$0: cannot dup STDOUT: $!\n";
309 0 0         exec(@_)or die "$0: cannot exec `@_': $!\n";
310             }
311 0           my @output;
312 0           while ()
313             {
314 0           s/[\r\n]+$//;
315 0           push(@output, $_);
316             }
317 0           close(SAFE_READ);
318 0           my $result = $?;
319 0           my $exit = $result >> 8;
320 0           my $signal = $result & 127;
321 0 0         my $cd = $result & 128 ? "with core dump" : "";
322 0 0 0       if ($signal or $cd)
323             {
324 0           warn "$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n";
325             }
326 0 0         if (wantarray)
327             {
328 0           return ($result, @output);
329             }
330             else
331             {
332 0           return $result;
333             }
334             }
335             1;
336            
337             __END__