File Coverage

blib/lib/Net/MirrorDir.pm
Criterion Covered Total %
statement 169 218 77.5
branch 38 74 51.3
condition 25 58 43.1
subroutine 32 35 91.4
pod 7 8 87.5
total 271 393 68.9


line stmt bran cond sub pod time code
1             #*** MirrorDir.pm ***#
2             # Copyright (C) 2006 - 2009 by Torsten Knorr
3             # create-soft@freenet.de
4             # All rights reserved!
5             #-------------------------------------------------
6 1     1   24663 use strict;
  1         2  
  1         766  
7             #-------------------------------------------------
8             package Net::MirrorDir::LocalDir;
9 7   33 7   11 sub TIESCALAR { my ($class, $obj) = @_; return bless(\$obj, $class || ref($class)); }
  7         35  
10 11   100 11   32 sub STORE { $_[1] ||= '.'; ${$_[0]}->{_regex_localdir} = qr!^\Q$_[1]\E!; }
  11         146  
  11         66  
11 40     40   80 sub FETCH { return ${$_[0]}->{_localdir}; }
  40         2846  
12             #-------------------------------------------------
13             package Net::MirrorDir::RemoteDir;
14 7   33 7   13 sub TIESCALAR { my($class, $obj) = @_; return bless(\$obj, $class || ref($class)); }
  7         35  
15 11   100 11   40 sub STORE { $_[1] ||= ''; ${$_[0]}->{_regex_remotedir} = qr!^\Q$_[1]\E!; }
  11         127  
  11         57  
16 30     30   35 sub FETCH { return ${$_[0]}->{_remotedir}; }
  30         119  
17             #-------------------------------------------------
18             package Net::MirrorDir::Exclusions;
19 7   33 7   12 sub TIESCALAR { my ($class, $obj) = @_; return bless(\$obj, $class || ref($class)); }
  7         30  
20 44     44   69 sub STORE { @{${$_[0]}->{_regex_exclusions}} = map { qr/$_/ } @{${$_[0]}->{_exclusions}}; }
  44         57  
  44         694  
  362         13368  
  44         46  
  44         132  
21 60     60   152 sub FETCH { return ${$_[0]}->{_exclusions}; }
  60         526  
22             #-------------------------------------------------
23             package Net::MirrorDir::Subset;
24 7   33 7   12 sub TIESCALAR { my ($class, $obj) = @_; return bless(\$obj, $class || ref($class)); }
  7         31  
25 43     43   134 sub STORE { @{${$_[0]}->{_regex_subset}} = map { qr/$_/ } @{${$_[0]}->{_subset}}; }
  43         55  
  43         1480  
  360         3384  
  43         58  
  43         132  
26 58     58   81 sub FETCH { return ${$_[0]}->{_subset}; }
  58         744  
27             #-------------------------------------------------
28             package Net::MirrorDir::Connection;
29 7   33 7   32 sub TIESCALAR { return bless($_[1], $_[0] || ref($_[0])); }
30 7     7   10 sub STORE { ${$_[0]} = $_[1]; }
  7         27  
31 7     7   10 sub FETCH { return ${$_[0]}; }
  7         31  
32             #-------------------------------------------------
33             package Net::MirrorDir;
34 1     1   1032 use Net::FTP;
  1         65723  
  1         68  
35 1     1   12 use vars '$AUTOLOAD';
  1         8  
  1         2081  
36             $Net::MirrorDir::VERSION = '0.20';
37             $Net::MirrorDir::_connection = undef;
38             #-------------------------------------------------
39             sub new
40             {
41 7     7 1 453 my ($class, %arg) = @_;
42 7 50 33     1437 my $self =
      33        
      33        
      50        
      100        
43             {
44             _ftpserver => $arg{ftpserver} || warn("missing ftpservername"),
45             _user => $arg{user} || warn("missing username"),
46             _pass => $arg{pass} || warn("missing password"),
47             _timeout => $arg{timeout} || 30,
48             _connection =>
49             $Net::MirrorDir::_connection || $arg{connection} || undef,
50             _debug => defined($arg{debug}) ? $arg{debug} : 1
51             };
52 7   33     29 bless($self, $class || ref($class));
53 7         45 tie($self->{_localdir}, "Net::MirrorDir::LocalDir", $self);
54 7         41 tie($self->{_remotedir}, "Net::MirrorDir::RemoteDir", $self);
55 7         34 tie($self->{_exclusions}, "Net::MirrorDir::Exclusions", $self);
56 7         27 tie($self->{_subset}, "Net::MirrorDir::Subset", $self);
57 7         25 tie(
58             $self->{_connection},
59             "Net::MirrorDir::Connection",
60             \$Net::MirrorDir::_connection
61             );
62 7   100     44 $self->{_localdir} = $arg{localdir} || '.';
63 7   100     39 $self->{_remotedir} = $arg{remotedir} || '';
64 7   100     38 $self->{_exclusions} = $arg{exclusions} || [];
65 7   50     42 $self->{_subset} = $arg{subset} || [];
66 7 50       30 $self->_Init(%arg) if(__PACKAGE__ ne ref($self));
67 7         31 return $self;
68             }
69             #-------------------------------------------------
70             sub _Init
71             {
72 1     1   1402 warn("\n\ncall to abstract method _Init() from package: " . ref($_[0]) . "\n");
73 1         11 return(0);
74             }
75             #------------------------------------------------
76             sub Connect
77             {
78 1     1 1 6 my ($self) = @_;
79 1 50       4 return($Net::MirrorDir::_connection) if($self->IsConnection());
80             eval
81 1         2 {
82 1 50       13 $Net::MirrorDir::_connection = Net::FTP->new(
83             $self->{_ftpserver},
84             Debug => $self->{_debug},
85             Timeout => $self->{_timeout},
86             ) or warn("Cannot connect to $self->{_ftpserver} : $@\n");
87 1 0       36640 if($Net::MirrorDir::_connection->login($self->{_user}, $self->{_pass}))
88             {
89 0         0 $Net::MirrorDir::_connection->binary();
90             }
91             else
92             {
93 0         0 $Net::MirrorDir::_connection->quit();
94 0         0 $Net::MirrorDir::_connection = undef;
95 0 0       0 print("\nerror in login\n") if($self->{_debug});
96 0         0 return 0;
97             }
98 0         0 return 1;
99             };
100             }
101             #-------------------------------------------------
102             sub IsConnection
103             {
104 2     2 0 4 return eval { $Net::MirrorDir::_connection->pwd(); };
  2         39  
105             }
106             #-------------------------------------------------
107             sub Quit
108             {
109 1     1 1 3 my ($self) = @_;
110 1 50       3 $Net::MirrorDir::_connection->quit() if($self->IsConnection());
111 1         2 $Net::MirrorDir::_connection = undef;
112 1         7 return 1;
113             }
114             #-------------------------------------------------
115             sub ReadLocalDir
116             {
117 11     11 1 29 my ($self, $dir) = @_;
118 11   66     78 $dir ||= $self->{_localdir};
119 11 50       287 return({}, {}) unless(-d $dir);
120 11         35 $self->{_localfiles} = {};
121 11         43 $self->{_localdirs} = {};
122             $self->{_readlocaldir} = sub
123             {
124 130     130   211 my ($self, $p) = @_;
125 130 100       2973 if(-f $p)
    50          
126             {
127 53 100       77 if(!@{$self->{_regex_subset}})
  53         145  
128             {
129 14         48 $self->{_localfiles}{$p} = 1;
130 14         48 return($self->{_localfiles}, $self->{_localdirs});
131             }
132 39         513 for(@{$self->{_regex_subset}})
  39         99  
133             {
134 57 100       451 if($p =~ $_)
135             {
136 26         72 $self->{_localfiles}{$p} = 1;
137 26         43 last;
138             }
139             }
140 39         139 return($self->{_localfiles}, $self->{_localdirs});
141             }
142             elsif(-d $p)
143             {
144 77         206 $self->{_localdirs}{$p} = 1;
145 77 50       1372 opendir(PATH, $p) or die("error in opendir $p $!\n");
146 77 100       971 my @files = grep { $_ ne '.' and $_ ne '..' } readdir(PATH);
  297         1182  
147 77         3093 closedir(PATH);
148 77         179 for my $file (@files)
149             {
150 143 100       163 next if(grep { $file =~ $_ } @{$self->{_regex_exclusions}});
  104         446  
  143         354  
151 119         697 $self->{_readlocaldir}->($self, "$p/$file");
152             }
153 77         249 return($self->{_localfiles}, $self->{_localdirs});
154             }
155 0         0 warn("$p is neither a file nor a directory\n");
156 0         0 return($self->{_localfiles}, $self->{_localdirs});
157 11         121 };
158 11 50       555 opendir(PATH, $dir) or die("error in opendir $dir $!\n");
159 11 100       196 my @files = grep { $_ ne '.' and $_ ne '..' } readdir(PATH);
  33         243  
160 11         182 closedir(PATH);
161 11         26 for my $file (@files)
162             {
163 11 50       18 next if(grep { $file =~ $_ } @{$self->{_regex_exclusions}});
  8         51  
  11         42  
164 11         49 $self->{_readlocaldir}->($self, "$dir/$file");
165             }
166 11         81 return($self->{_localfiles}, $self->{_localdirs});
167             }
168             #-------------------------------------------------
169             sub ReadRemoteDir
170             {
171 0     0 1 0 my ($self, $dir) = @_;
172 0   0     0 $dir ||= $self->{_remotedir};
173 0 0       0 return({}, {}) unless(eval { $Net::MirrorDir::_connection->cwd($dir); });
  0         0  
174 0 0       0 return({}, {}) unless($Net::MirrorDir::_connection->cwd());
175 0         0 $self->{_remotefiles} = {};
176 0         0 $self->{_remotedirs} = {};
177             $self->{_readremotedir} = sub
178             {
179 0     0   0 my ($self, $p) = @_;
180 0         0 my (@info, $name, $np, $ra_lines);
181 0         0 my $count = 0;
182 0   0     0 until($ra_lines = $Net::MirrorDir::_connection->dir($p) || ++$count > 3)
183             {
184 0 0       0 $self->Connect() unless($Net::MirrorDir::_connection->abort());
185             }
186 0 0       0 if($self->{_debug})
187             {
188 0         0 print("\nreturnvalues from \n");
189 0         0 print("$_\n") for(@{$ra_lines});
  0         0  
190             }
191 0         0 for my $line (@{$ra_lines})
  0         0  
192             {
193 0         0 @info = split(/\s+/, $line);
194 0         0 $name = $info[$#info];
195 0 0 0     0 next if($name eq '.' || $name eq '..');
196 0         0 $np = "$p/$name";
197 0 0       0 next if(grep { $np =~ $_ } @{$self->{_regex_exclusions}});
  0         0  
  0         0  
198 0 0       0 if($line =~ m/^-/)
    0          
199             {
200 0         0 $self->{_remotefiles}{$np} = 1
201 0 0       0 unless(@{$self->{_regex_subset}});
202 0         0 for(@{$self->{_regex_subset}})
  0         0  
203             {
204 0 0       0 if($np =~ $_)
205             {
206 0         0 $self->{_remotefiles}{$np} = 1;
207 0         0 last;
208             }
209             }
210             }
211             elsif($line =~ m/^d/)
212             {
213 0         0 $self->{_remotedirs}{$np} = 1;
214 0         0 $self->{_readremotedir}->($self, $np);
215             }
216             else
217             {
218 0         0 warn("error can not get info: $line\n");
219             }
220             }
221 0         0 return($self->{_remotefiles}, $self->{_remotedirs});
222 0         0 };
223 0         0 return $self->{_readremotedir}->($self, $dir);
224             }
225             #-------------------------------------------------
226             sub LocalNotInRemote
227             {
228 5     5 1 11 my ($self, $rh_lp, $rh_rp) = @_;
229 5         11 my @lnir = ();
230 5         8 my $rp;
231 5         6 for my $lp (keys(%{$rh_lp}))
  5         22  
232             {
233 28         39 $rp = $lp;
234 28         245 $rp =~ s!$self->{_regex_localdir}!$self->{_remotedir}!;
235 28 100       101 push(@lnir, $lp) unless(defined($rh_rp->{$rp}));
236             }
237 5         34 return \@lnir;
238             }
239             #-------------------------------------------------
240             sub RemoteNotInLocal
241             {
242 5     5 1 13 my ($self, $rh_lp, $rh_rp) = @_;
243 5         9 my @rnil = ();
244 5         9 my $lp;
245 5         7 for my $rp (keys(%{$rh_rp}))
  5         22  
246             {
247 28         39 $lp = $rp;
248 28         165 $lp =~ s!$self->{_regex_remotedir}!$self->{_localdir}!;
249 28 100       97 push(@rnil, $rp) unless(defined($rh_lp->{$lp}));
250             }
251 5         30 return \@rnil;
252             }
253             #-------------------------------------------------
254             sub AUTOLOAD
255             {
256 1     1   9 no strict "refs";
  1         2  
  1         553  
257 51     51   2007 my ($self, $value) = @_;
258 51 100       813 if($AUTOLOAD =~ m/.*::(?i:get)_*(\w+)/)
    100          
    100          
259             {
260 24         91 my $attr = lc($1);
261 24         53 $attr = '_' . $attr;
262 24 100       70 if(exists($self->{$attr}))
263             {
264 21         82 *{$AUTOLOAD} = sub
265             {
266 69     69   1490 return $_[0]->{$attr};
267 21         77 };
268 21         171 return $self->{$attr};
269             }
270             else
271             {
272 3         244 warn("\nNO such attribute : $attr\n");
273             }
274             }
275             elsif($AUTOLOAD =~ m/.*::(?i:set)_*(\w+)/)
276             {
277 20         56 my $attr = lc($1);
278 20         47 $attr = '_' . $attr;
279 20 100       61 if(exists($self->{$attr}))
280             {
281 19         86 *{$AUTOLOAD} = sub
282             {
283 19     19   15313 $_[0]->{$attr} = $_[1];
284 19         87 return 1;
285 19         70 };
286 19         158 $self->{$attr} = $value;
287 19         111 return 1;
288             }
289             else
290             {
291 1         88 warn("\nNO such attribute : $attr\n");
292             }
293             }
294             elsif($AUTOLOAD =~ m/.*::(?i:add)_*(\w+)/)
295             {
296 6         20 my $attr = lc($1);
297 6         13 $attr = '_' . $attr;
298 6 100       22 if(ref($self->{$attr}) eq "ARRAY")
299             {
300 4         15 *{$AUTOLOAD} = sub
301             {
302 54     54   9694 $_[0]->{$attr} = [@{$_[0]->{$attr}}, $_[1]];
  54         10363  
303 54         320 return 1;
304 4         15 };
305 4         8 $self->{$attr} = [@{$self->{$attr}}, $value];
  4         21  
306 4         20 return 1;
307             }
308             else
309             {
310 2         318 warn("\nNO such attribute or NOT a array reference: $attr\n");
311             }
312             }
313             else
314             {
315 1         60 warn("\nno such method : $AUTOLOAD\n");
316             }
317 7         47 return 0;
318             }
319             #-------------------------------------------------
320             sub DESTROY
321             {
322 0     0     my ($self) = @_;
323 0 0 0       print($self || ref($self) . "object destroyed\n") if($self->{_debug});
324             }
325             #-------------------------------------------------
326             1;
327             #-------------------------------------------------
328             __END__