File Coverage

blib/lib/App/diffdir.pm
Criterion Covered Total %
statement 72 96 75.0
branch 24 44 54.5
condition 3 12 25.0
subroutine 11 14 78.5
pod 0 7 0.0
total 110 173 63.5


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   73548 use Moo;
  3         33673  
  3         14  
10 3     3   4285 use strict;
  3         6  
  3         58  
11 3     3   13 use warnings;
  3         5  
  3         84  
12 3     3   700 use Data::Dumper qw/Dumper/;
  3         6964  
  3         171  
13 3     3   614 use English qw/ -no_match_vars /;
  3         3662  
  3         19  
14 3     3   1961 use Path::Tiny;
  3         14895  
  3         174  
15 3     3   1587 use Text::Diff;
  3         25977  
  3         3482  
16              
17             our $VERSION = 0.8;
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 4717 my ($self, @dirs) = @_;
40              
41 1         6 my %found = $self->get_files(@dirs);
42              
43 1         4 for my $file (keys %found) {
44 6         11 my $last_dir = $dirs[0];
45 6         9 my $diff_count = 0;
46              
47 6 100       18 if ( ! $found{$file}{$last_dir} ) {
48 1         4 $found{$file}{$last_dir} = {
49             name => path( $last_dir, $file),
50             diff => 'missing',
51             };
52             }
53              
54 6         49 for my $dir (@dirs[1 .. @dirs - 1]) {
55 6 100       29 if ( ! $found{$file}{$dir} ) {
    100          
    100          
56 1         6 $found{$file}{$dir} = {
57             name => path( $dir, $file),
58             diff => 'missing',
59             };
60 1         35 $diff_count++;
61             }
62             elsif ( ! -e $found{$file}{$last_dir}{name} ) {
63 1         26 $found{$file}{$dir}{diff} = 'added';
64 1         3 $diff_count++;
65             }
66 4         85 elsif ( my $diff = eval { $self->dodiff( ''.path($last_dir, $file), ''.path($dir, $file) ) } ) {
67 1         3 $found{$file}{$dir}{diff} = $diff;
68 1         2 $diff_count++;
69             }
70 6 50       21 warn $@ if $@;
71 6         14 $last_dir = $dir;
72             }
73              
74 6 100       14 if ( !$diff_count ) {
75 3         14 delete $found{$file};
76             }
77             }
78              
79 1         10 return %found;
80             }
81              
82             sub get_files {
83 2     2 0 79550 my ($self, @dirs) = @_;
84 2         6 my %found;
85              
86 2         7 for my $dir (@dirs) {
87 4         14 $dir =~ s{/$}{};
88 4         29 my @found = $self->find_files($dir);
89 4         10 for my $file (@found) {
90 20         35 my $base = $file;
91 20 50       34 if ( $dir ne '.' ) {
92             # remove the base directory from the file name
93 20         146 $base =~ s/^\Q$dir\E\/?//;
94             }
95 20         234 $found{$base}{$dir} = {
96             name => $file,
97             };
98             }
99             }
100              
101 2         17 return %found;
102             }
103              
104             sub find_files {
105 6     6 0 4102 my ($self, $dir) = @_;
106 6         23 my @files = path($dir)->children;
107 6         1567 my @found;
108              
109             FILE:
110 6         43 while ( my $file = shift @files ) {
111 34 100       1331 next FILE if $file->basename =~ /^[.].*[.]sw[n-z]$|^[.](?:svn|bzr|git)$|CVS|RCS$|cover_db|_build|Build$|blib/;
112 28 100 66     762 next FILE if $self->{exclude} && grep {$file =~ /$_/} @{ $self->{exclude} };
  4         23  
  28         90  
113              
114 27         67 push @found, $file;
115              
116 27 100       111 if ( -d $file ) {
117 6         113 push @files, $file->children;
118             }
119             }
120              
121 6         134 return @found;
122             }
123              
124             my $which_diff;
125             sub dodiff {
126 4     4 0 254 my ($self, $file1, $file2) = @_;
127              
128 4 100       9 if ( ! $which_diff ) {
129 1 50 33     11 $which_diff = $self->ignore_space_change || $self->ignore_all_space
130             ? 'mydiff'
131             : 'text';
132             }
133              
134 4 50       7 if ( $which_diff eq 'mydiff' ) {
135 0         0 return $self->mydiff($file1, $file2);
136             }
137             else {
138 4         15 my $diff = diff($file1, $file2);
139 4 100       1650 return (length $diff, "diff $file1 $file2") if $diff;
140             }
141              
142 3         13 return;
143             }
144              
145             sub mydiff {
146 0     0 0   my ($self, $file1, $file2) = @_;
147              
148 0 0 0       return if !$self->follow && (-l $file1 || -l $file2);
      0        
149              
150 0           my $file1_q = shell_quote($file1);
151 0           my $file2_q = shell_quote($file2);
152              
153 0           my $cmd = '/usr/bin/diff';
154 0 0         if ( $self->ignore_space_change ) {
155 0           $cmd .= ' --ignore-space-change';
156             }
157 0 0         if ( $self->ignore_all_space ) {
158 0           $cmd .= ' --ignore-all-space';
159             }
160 0           $cmd .= " $file1_q $file2_q";
161 0 0         my $diff
    0          
162             = -s $file1 != -s $file2 ? abs( (-s $file1) - (-s $file2) )
163             : $self->fast ? 0
164             : length ''.`$cmd`;
165              
166 0 0         if ($diff) {
167 0 0         warn "$self->cmd $file1_q $file2_q\n" if $self->verbose;
168 0           return ( $diff, "$self->cmd $file1_q $file2_q" );
169             }
170              
171 0           return;
172             }
173              
174             sub shell_quote {
175 0     0 0   my ($text) = @_;
176              
177 0 0         if ($text =~ /[\s$|><;#]/xms) {
178 0           $text =~ s/'/'\\''/gxms;
179 0           $text = "'$text'";
180             }
181              
182 0           return $text;
183             }
184              
185             sub basename {
186 0     0 0   my ($self, $dir, $file) = @_;
187 0           $file =~ s{^$dir/?}{};
188 0           return $file;
189             }
190              
191             1;
192              
193             __END__