File Coverage

blib/lib/App/diffdir.pm
Criterion Covered Total %
statement 70 94 74.4
branch 23 42 54.7
condition 3 12 25.0
subroutine 11 14 78.5
pod 0 7 0.0
total 107 169 63.3


line stmt bran cond sub pod time code
1             package App::diffdir;
2              
3             # Created on: 2015-03-05 19:52:53
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 3     3   73799 use Moo;
  3         34766  
  3         15  
10 3     3   4441 use strict;
  3         7  
  3         57  
11 3     3   15 use warnings;
  3         7  
  3         92  
12 3     3   681 use Data::Dumper qw/Dumper/;
  3         6853  
  3         198  
13 3     3   625 use English qw/ -no_match_vars /;
  3         3612  
  3         31  
14 3     3   2093 use Path::Tiny;
  3         13279  
  3         186  
15 3     3   1649 use Text::Diff;
  3         26660  
  3         3594  
16              
17             our $VERSION = 0.7;
18              
19             has files => (
20             is => 'rw',
21             default => sub {{}},
22             );
23             has exclude => (
24             is => 'rw',
25             default => sub {[]},
26             );
27             has [qw/
28             cmd
29             fast
30             follow
31             ignore_all_space
32             ignore_space_change
33             verbose
34             /] => (
35             is => 'rw',
36             );
37              
38             sub differences {
39 1     1 0 4468 my ($self, @dirs) = @_;
40              
41 1         5 my %found = $self->get_files(@dirs);
42              
43 1         5 for my $file (keys %found) {
44 6         12 my $last_dir = $dirs[0];
45 6         9 my $diff_count = 0;
46              
47 6 100       18 if ( ! $found{$file}{$last_dir} ) {
48 1         3 $found{$file}{$last_dir} = {
49             name => path( $last_dir, $file),
50             diff => 'missing',
51             };
52             }
53              
54 6         43 for my $dir (@dirs[1 .. @dirs - 1]) {
55 6 100       30 if ( ! $found{$file}{$dir} ) {
    100          
    100          
56 1         5 $found{$file}{$dir} = {
57             name => path( $dir, $file),
58             diff => 'missing',
59             };
60 1         39 $diff_count++;
61             }
62             elsif ( ! -e $found{$file}{$last_dir}{name} ) {
63 1         27 $found{$file}{$dir}{diff} = 'added';
64 1         2 $diff_count++;
65             }
66 4         85 elsif ( my $diff = eval { $self->dodiff( ''.path($last_dir, $file), ''.path($dir, $file) ) } ) {
67 1         4 $found{$file}{$dir}{diff} = $diff;
68 1         2 $diff_count++;
69             }
70 6 50       19 warn $@ if $@;
71 6         11 $last_dir = $dir;
72             }
73              
74 6 100       17 if ( !$diff_count ) {
75 3         14 delete $found{$file};
76             }
77             }
78              
79 1         8 return %found;
80             }
81              
82             sub get_files {
83 2     2 0 4919 my ($self, @dirs) = @_;
84 2         6 my %found;
85              
86 2         6 for my $dir (@dirs) {
87 4         11 my @found = $self->find_files($dir);
88 4         10 for my $file (@found) {
89 20         29 my $base = $file;
90 20         111 $base =~ s/^$dir\/?//;
91 20         201 $found{$base}{$dir} = {
92             name => $file,
93             };
94             }
95             }
96              
97 2         15 return %found;
98             }
99              
100             sub find_files {
101 6     6 0 4381 my ($self, $dir) = @_;
102 6         18 my @files = path($dir)->children;
103 6         1536 my @found;
104              
105             FILE:
106 6         34 while ( my $file = shift @files ) {
107 34 100       1331 next FILE if $file->basename =~ /^[.].*[.]sw[n-z]$|^[.](?:svn|bzr|git)$|CVS|RCS$/;
108 28 100 66     766 next FILE if $self->{exclude} && grep {$file =~ /$_/} @{ $self->{exclude} };
  4         29  
  28         107  
109              
110 27         66 push @found, $file;
111              
112 27 100       77 if ( -d $file ) {
113 6         108 push @files, $file->children;
114             }
115             }
116              
117 6         184 return @found;
118             }
119              
120             my $which_diff;
121             sub dodiff {
122 4     4 0 264 my ($self, $file1, $file2) = @_;
123              
124 4 100       13 if ( ! $which_diff ) {
125 1 50 33     14 $which_diff = $self->ignore_space_change || $self->ignore_all_space
126             ? 'mydiff'
127             : 'text';
128             }
129              
130 4 50       10 if ( $which_diff eq 'mydiff' ) {
131 0         0 return $self->mydiff($file1, $file2);
132             }
133             else {
134 4         13 my $diff = diff($file1, $file2);
135 4 100       1709 return (length $diff, "diff $file1 $file2") if $diff;
136             }
137              
138 3         12 return;
139             }
140              
141             sub mydiff {
142 0     0 0   my ($self, $file1, $file2) = @_;
143              
144 0 0 0       return if !$self->follow && (-l $file1 || -l $file2);
      0        
145              
146 0           my $file1_q = shell_quote($file1);
147 0           my $file2_q = shell_quote($file2);
148              
149 0           my $cmd = '/usr/bin/diff';
150 0 0         if ( $self->ignore_space_change ) {
151 0           $cmd .= ' --ignore-space-change';
152             }
153 0 0         if ( $self->ignore_all_space ) {
154 0           $cmd .= ' --ignore-all-space';
155             }
156 0           $cmd .= " $file1_q $file2_q";
157 0 0         my $diff
    0          
158             = -s $file1 != -s $file2 ? abs( (-s $file1) - (-s $file2) )
159             : $self->fast ? 0
160             : length ''.`$cmd`;
161              
162 0 0         if ($diff) {
163 0 0         warn "$self->cmd $file1_q $file2_q\n" if $self->verbose;
164 0           return ( $diff, "$self->cmd $file1_q $file2_q" );
165             }
166              
167 0           return;
168             }
169              
170             sub shell_quote {
171 0     0 0   my ($text) = @_;
172              
173 0 0         if ($text =~ /[\s$|><;#]/xms) {
174 0           $text =~ s/'/'\\''/gxms;
175 0           $text = "'$text'";
176             }
177              
178 0           return $text;
179             }
180              
181             sub basename {
182 0     0 0   my ($self, $dir, $file) = @_;
183 0           $file =~ s{^$dir/?}{};
184 0           return $file;
185             }
186              
187             1;
188              
189             __END__