File Coverage

blib/lib/Directory/Diff.pm
Criterion Covered Total %
statement 58 109 53.2
branch 20 50 40.0
condition 6 15 40.0
subroutine 8 11 72.7
pod 6 6 100.0
total 98 191 51.3


line stmt bran cond sub pod time code
1             package Directory::Diff;
2             require Exporter;
3             @ISA = qw(Exporter);
4             @EXPORT_OK = qw/ls_dir get_only get_diff directory_diff
5             default_diff default_dir_only/;
6             %EXPORT_TAGS = (
7             all => \@EXPORT_OK,
8             );
9 2     2   49997 use warnings;
  2         13  
  2         67  
10 2     2   12 use strict;
  2         4  
  2         70  
11             our $VERSION = '0.06';
12 2     2   10 use Carp qw/carp croak/;
  2         5  
  2         138  
13 2     2   12 use Cwd 'getcwd';
  2         5  
  2         100  
14 2     2   558 use File::Compare 'compare';
  2         1892  
  2         1706  
15              
16             sub ls_dir
17             {
18 6     6 1 10250 my ($dir, $verbose) = @_;
19 6 50 33     54 if (! $dir || ! -d $dir) {
20 0         0 croak "No such directory '$dir'";
21             }
22 6         9 my %ls;
23 6 50       13 if (! wantarray) {
24 0         0 die "bad call";
25             }
26 6         19 my $original_dir = getcwd ();
27 6         22 chdir ($dir);
28 6         77 opendir (my $dh, ".");
29 6         65 my @files = readdir ($dh);
30 6         14 for my $file (@files) {
31 20 100 100     49 if ($file eq '.' || $file eq '..') {
32 12         15 next;
33             }
34 8 100       49 if (-f $file) {
    50          
35 6         14 $ls{"$file"} = 1;
36             }
37             elsif (-d $file) {
38 2         9 my %subdir = ls_dir ($file);
39 2         4 for my $subdir_file (keys %subdir) {
40 2         7 $ls{"$file/$subdir_file"} = 1;
41             }
42 2         6 $ls{"$file/"} = 1;
43             }
44             else {
45 0         0 warn "Skipping unknown type of file $file.\n";
46             }
47             }
48 6         35 closedir ($dh);
49 6         20 chdir ($original_dir);
50 6 50       12 if ($verbose) {
51 0         0 for my $k (keys %ls) {
52 0         0 print "$k $ls{$k}\n";
53             }
54             }
55 6         30 return %ls;
56             }
57              
58             sub get_only
59             {
60 2     2 1 670 my ($ls_dir1_ref, $ls_dir2_ref, $verbose) = @_;
61              
62 2 50 33     14 if (ref ($ls_dir1_ref) ne "HASH" ||
63             ref ($ls_dir2_ref) ne "HASH") {
64 0         0 croak "get_only requires hash references as arguments";
65             }
66 2         2 my %only;
67              
68             # d1e = directory one entry
69            
70 2         6 for my $d1e (keys %$ls_dir1_ref) {
71 7 100       12 if (! $ls_dir2_ref->{$d1e}) {
72 5         8 $only{$d1e} = 1;
73 5 50       9 if ($verbose) {
74 0         0 print "$d1e is only in first directory.\n";
75             }
76             }
77             }
78 2 50       5 if (! wantarray) {
79 0         0 croak "bad call";
80             }
81 2         8 return %only;
82             }
83              
84             sub get_diff
85             {
86 2     2 1 10 my ($dir1, $ls_dir1_ref, $dir2, $ls_dir2_ref) = @_;
87 2 50 33     10 if (ref ($ls_dir1_ref) ne "HASH" ||
88             ref ($ls_dir2_ref) ne "HASH") {
89 0         0 croak "get_diff requires hash references as arguments 2 and 4";
90             }
91 2         2 my %different;
92 2         7 for my $file (keys %$ls_dir1_ref) {
93 4         7 my $d1file = "$dir1/$file";
94 4 50       8 if ($ls_dir2_ref->{$file}) {
95 4 100       26 if (! -f $d1file) {
96             # croak "Bad file / directory combination $d1file";
97 1         2 next;
98             }
99 3         6 my $d2file = "$dir2/$file";
100 3 100       9 if (compare ($d1file, $d2file) != 0) {
101 2         133 $different{$file} = 1;
102             }
103             }
104             }
105 2 50       86 if (! wantarray) {
106 0         0 croak "Bad call";
107             }
108 2         9 return %different;
109             }
110              
111             sub directory_diff
112             {
113 0     0 1   my ($dir1, $dir2, $callback_ref, $verbose) = @_;
114 0 0 0       if (! $dir1 || ! $dir2) {
115 0           croak "directory_diff requires two directory names";
116             }
117 0 0         if (! -d $dir1) {
118 0           croak "directory_diff: first directory '$dir1' does not exist";
119             }
120 0 0         if (! -d $dir2) {
121 0           croak "directory_diff: second directory '$dir2' does not exist";
122             }
123 0 0         if ($verbose) {
124 0           print "Directory diff of $dir1 and $dir2 in progress ...\n";
125             }
126 0 0         if (! $callback_ref) {
127 0           croak "directory_diff: no callbacks supplied";
128             }
129 0 0         if (ref $callback_ref ne "HASH") {
130 0           croak "directory_diff: callback not hash reference";
131             }
132 0           my %ls_dir1 = ls_dir ($dir1);
133 0           my %ls_dir2 = ls_dir ($dir2);
134             # Data to pass to called back functions.
135 0           my $data = $callback_ref->{data};
136             # Call back a function on each file which is only in directory 1.
137 0           my $d1cb = $callback_ref->{dir1_only};
138 0 0         if ($d1cb) {
139             # Files which are only in directory 1.
140 0           my %dir1_only = get_only (\%ls_dir1, \%ls_dir2, $verbose);
141 0           for my $file (keys %dir1_only) {
142 0           &{$d1cb} ($data, $dir1, $file, $verbose);
  0            
143             }
144             }
145             # Call back a function on each file which is only in directory 2.
146 0           my $d2cb = $callback_ref->{dir2_only};
147 0 0         if ($d2cb) {
148             # Files which are only in directory 2.
149 0           my %dir2_only = get_only (\%ls_dir2, \%ls_dir1, $verbose);
150 0           for my $file (keys %dir2_only) {
151 0           &{$d2cb} ($data, $dir2, $file, $verbose);
  0            
152             }
153             }
154             # Call back a function on each file which is in both directories
155             # but different.
156 0           my $diff_cb = $callback_ref->{diff};
157 0 0         if ($diff_cb) {
158             # Files which are in both directories but are different.
159 0           my %diff_files = get_diff ($dir1, \%ls_dir1, $dir2, \%ls_dir2, $verbose);
160 0           for my $file (keys %diff_files) {
161 0           &{$diff_cb} ($data, $dir1, $dir2, $file, $verbose);
  0            
162             }
163             }
164 0 0         if (defined wantarray) {
165 0           carp "directory_diff does not return a meaningful value";
166             }
167 0           return;
168             }
169              
170             sub default_dir_only
171             {
172 0     0 1   my ($data, $dir, $file) = @_;
173 0           print "File '$file' is only in '$dir'.\n";
174             }
175              
176             sub default_diff
177             {
178 0     0 1   my ($data, $dir1, $dir2, $file) = @_;
179 0           print "File '$file' is different between '$dir1' and '$dir2'.\n";
180             }
181              
182             1;
183