File Coverage

blib/lib/Directory/Diff.pm
Criterion Covered Total %
statement 84 105 80.0
branch 31 50 62.0
condition 7 15 46.6
subroutine 9 9 100.0
pod 4 4 100.0
total 135 183 73.7


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