File Coverage

blib/lib/App/MBUtiny/Util.pm
Criterion Covered Total %
statement 47 164 28.6
branch 1 76 1.3
condition 1 55 1.8
subroutine 16 27 59.2
pod 10 10 100.0
total 75 332 22.5


line stmt bran cond sub pod time code
1             package App::MBUtiny::Util; # $Id: Util.pm 120 2019-07-01 11:57:45Z abalama $
2 4     4   30 use strict;
  4         9  
  4         123  
3 4     4   20 use utf8;
  4         9  
  4         23  
4              
5             =encoding utf-8
6              
7             =head1 NAME
8              
9             App::MBUtiny::Util - Internal utilities used by App::MBUtiny module
10              
11             =head1 VERSION
12              
13             Version 1.02
14              
15             =head1 SYNOPSIS
16              
17             use App::MBUtiny::Util qw/
18             filesize explain hide_password md5sum
19             resolv sha1sum
20             /;
21              
22             my $fsize = filesize( $file );
23             print explain( $object );
24             print hide_password('http://user:password@example.com');
25             my $md5 = md5sum( $file );
26             my $name = resolv( $IPv4 );
27             my $sha1 = sha1sum( $filename );
28              
29             =head1 DESCRIPTION
30              
31             Internal utility functions
32              
33             =over 8
34              
35             =item B
36              
37             print explain( $object );
38              
39             Returns Data::Dumper dump
40              
41             =item B
42              
43             my $fsize = filesize( $file );
44              
45             Returns file size
46              
47             =item B
48              
49             print hide_password('http://user:password@example.com'); # 'http://user:*****@example.com'
50              
51             Returns specified URL but without password
52              
53             =item B
54              
55             my $md5 = md5sum( $filename );
56              
57             See L
58              
59             =item B
60              
61             my $anode = node2anode({});
62              
63             Returns array of nodes
64              
65             =item B
66              
67             my ($user, $password) = parse_credentials( 'http://user:password@example.com' );
68             my ($user, $password) = parse_credentials( new URI('http://user:password@example.com') );
69              
70             Returns credentials pair by URL or URI object
71              
72             =item B
73              
74             my $name = resolv( $IPv4 );
75             my $ip = resolv( $name );
76              
77             Resolv ip to a hostname or hostname to ip. See L, L
78             and L
79              
80             =item B
81              
82             my $hash = set2attr({set => ["AttrName Value"]}); # {"AttrName" => "Value"}
83              
84             Converts attributes from the "set" format to regular hash
85              
86             =item B
87              
88             my $sha1 = sha1sum( $filename );
89              
90             See L
91              
92             =item B
93              
94             xcopy( $src_dir, $dst_dir, [ ... exclude rel. paths ... ] );
95              
96             Exclusive copying all objects (files/directories) from $src_dir directory into $dst_dir
97             directory without specified relative paths. The function returns status of work
98              
99             xcopy( "/source/folder", "/destination/folder" )
100             or die "Can't copy directory";
101              
102             # Copying without foo and bar/baz files/directories
103             xcopy( "/source/folder", "/destination/folder", [qw( foo bar/baz )] )
104             or die "Can't copy directory";
105              
106             =back
107              
108             =head1 HISTORY
109              
110             See C file
111              
112             =head1 AUTHOR
113              
114             Serż Minus (Sergey Lepenkov) L Eabalama@cpan.orgE
115              
116             =head1 COPYRIGHT
117              
118             Copyright (C) 1998-2019 D&D Corporation. All Rights Reserved
119              
120             =head1 LICENSE
121              
122             This program is free software; you can redistribute it and/or
123             modify it under the same terms as Perl itself.
124              
125             See C file and L
126              
127             =cut
128              
129 4     4   224 use vars qw/ $VERSION @EXPORT_OK /;
  4         16  
  4         314  
130             $VERSION = '1.02';
131              
132             our $DEBUG = 0;
133              
134 4     4   25 use Carp;
  4         8  
  4         249  
135 4     4   1143 use URI;
  4         9390  
  4         150  
136 4     4   27 use URI::Escape qw/uri_unescape/;
  4         7  
  4         294  
137 4     4   44 use File::Find;
  4         13  
  4         273  
138 4     4   1000 use File::Copy;
  4         4642  
  4         199  
139 4     4   26 use Digest::MD5;
  4         9  
  4         121  
140 4     4   1864 use Digest::SHA1;
  4         2720  
  4         199  
141 4     4   581 use Socket qw/inet_ntoa inet_aton AF_INET/;
  4         3639  
  4         337  
142 4     4   2373 use Data::Dumper; #$Data::Dumper::Deparse = 1;
  4         25009  
  4         258  
143 4     4   33 use CTK::ConfGenUtil;
  4         9  
  4         292  
144              
145             use constant {
146 4         246 DIRMODE => 0777,
147 4     4   25 };
  4         9  
148              
149 4     4   29 use base qw/Exporter/;
  4         7  
  4         7401  
150             @EXPORT_OK = qw/
151             filesize sha1sum md5sum
152             resolv
153             explain
154             xcopy
155             node2anode set2attr
156             parse_credentials hide_password
157             /;
158              
159             sub sha1sum {
160 0     0 1 0 my $f = shift;
161 0         0 my $sha1 = new Digest::SHA1;
162 0         0 my $sum = '';
163 0 0       0 return $sum unless -e $f;
164 0 0 0     0 open( my $sha1_fh, '<', $f) or (carp("Can't open '$f': $!") && return $sum);
165 0 0       0 if ($sha1_fh) {
166 0         0 binmode($sha1_fh);
167 0         0 $sha1->addfile($sha1_fh);
168 0         0 $sum = $sha1->hexdigest;
169 0         0 close($sha1_fh);
170             }
171 0         0 return $sum;
172             }
173             sub md5sum {
174 0     0 1 0 my $f = shift;
175 0         0 my $md5 = new Digest::MD5;
176 0         0 my $sum = '';
177 0 0       0 return $sum unless -e $f;
178 0 0 0     0 open( my $md5_fh, '<', $f) or (carp("Can't open '$f': $!") && return $sum);
179 0 0       0 if ($md5_fh) {
180 0         0 binmode($md5_fh);
181 0         0 $md5->addfile($md5_fh);
182 0         0 $sum = $md5->hexdigest;
183 0         0 close($md5_fh);
184             }
185 0         0 return $sum;
186             }
187             sub filesize {
188 0     0 1 0 my $f = shift;
189 0         0 my $filesize = 0;
190 0 0       0 $filesize = (stat $f)[7] if -e $f;
191 0         0 return $filesize;
192             }
193             sub resolv { # Resolving. See Socket::inet_ntoa
194             # Original: Sys::Net::resolv
195 0     0 1 0 my $name = shift;
196             # resolv ip to a hostname
197 0 0       0 if ($name =~ m/^\s*[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\s*$/) {
198 0         0 return scalar gethostbyaddr(inet_aton($name), AF_INET);
199             }
200             # resolv hostname to ip
201             else {
202 0         0 return inet_ntoa(scalar gethostbyname($name));
203             }
204             }
205             sub explain {
206 0     0 1 0 my $dumper = new Data::Dumper( [shift] );
207 0         0 $dumper->Indent(1)->Terse(1);
208 0 0       0 $dumper->Sortkeys(1) if $dumper->can("Sortkeys");
209 0         0 return $dumper->Dump;
210             }
211             sub xcopy {
212 0   0 0 1 0 my $object = shift || ''; # from
213 0   0     0 my $target = shift || ''; # to
214 0         0 my $exclude = shift; # exclude files
215              
216 0 0 0     0 carp("Source directory not exists: $object") && return
      0        
      0        
217             unless $object && (-e $object and -d $object);
218              
219 0 0 0     0 carp("Target directory not defined: $target") && return
220             unless $target;
221              
222 0 0 0     0 if ($exclude && ref($exclude) ne 'ARRAY') {
223 0         0 carp("The third argument must be reference to array containing list of files for excluding");
224 0         0 return;
225             } else {
226 0 0       0 $exclude = [] unless $exclude;
227             }
228              
229 0         0 my $ob = File::Spec->canonpath($object);
230 0         0 my $tg = File::Spec->canonpath($target);
231 0         0 my (@exf, @exd);
232 0         0 foreach (@$exclude) {
233 0         0 my $tf = File::Spec->canonpath(File::Spec->catfile($ob, $_));
234 0         0 my $td = File::Spec->canonpath(File::Spec->catdir($ob, $_));
235 0 0 0     0 if (-e $td && -d $td) {
236 0         0 push @exd, $td;
237             } else {
238 0         0 push @exf, $tf;
239             }
240             };
241              
242 0 0       0 if ($DEBUG) {
243 0         0 printf("#F: %s\n", $_) for @exf;
244 0         0 printf("#D: %s\n", $_) for @exd;
245             }
246              
247             find({
248             wanted => sub
249             {
250 0     0   0 my $f = File::Spec->canonpath($_);
251 0         0 my $p = File::Spec->abs2rel( $f, $ob );
252 0 0 0     0 if ((-e $f and -f $f) && (grep {$_ eq $f} @exf)) {
  0 0 0     0  
      0        
253 0 0       0 print ">F [SKIP] $f\n" if $DEBUG;
254 0         0 return 1;
255 0         0 } elsif (@exd && grep {_td($_,$f)} @exd) {
256 0 0       0 print ">D [SKIP] $f\n" if $DEBUG;
257 0         0 return 1;
258             } else {
259 0 0       0 if (-d $f) {
260 0         0 my $end = File::Spec->catdir($tg, $p);
261 0 0       0 print ">D $f -> $end\n" if $DEBUG;
262 0 0       0 unless (-e $end) {
263 0 0 0     0 mkdir($end,DIRMODE) or carp(sprintf("Can't create directoy \"%s\": ", $end, $!)) && return;
264 0         0 chmod scalar((stat($f))[2]), $end;
265             }
266             } else {
267 0         0 my $end = File::Spec->catfile($tg, $p);
268 0 0       0 print ">F $f -> $end\n" if $DEBUG;
269 0 0       0 unless (-e $end) {
270 0 0 0     0 copy($f,$end) or carp(sprintf("Copy failed \"%s\" -> \"%s\": %s", $f, $end, $!)) && return;
271 0         0 chmod scalar((stat($f))[2]), $end;
272             }
273             }
274             }
275             },
276 0         0 no_chdir => 1,
277             }, $ob,
278             );
279              
280 0 0       0 print "\n" if $DEBUG;
281 0         0 return 1;
282             }
283             sub node2anode {
284 5     5 1 168 my $n = shift;
285 5 50 33     129 return [] unless $n && ref($n) =~ /ARRAY|HASH/;
286 0 0         return [$n] if ref($n) eq 'HASH';
287 0           return $n;
288             }
289             sub parse_credentials {
290 0   0 0 1   my $url = shift || return ();
291 0 0         my $uri = (ref($url) eq 'URI') ? $url : URI->new($url);
292 0   0       my $info = $uri->userinfo() // "";
293 0           my $user = $info;
294 0           my $pass = $info;
295 0           $user =~ s/:.*//;
296 0           $pass =~ s/^[^:]*://;
297 0   0       return (uri_unescape($user // ''), uri_unescape($pass // ''));
      0        
298             }
299             sub hide_password {
300 0   0 0 1   my $url = shift || return "";
301 0   0       my $full = shift || 0; # 0 - starts, 1 - no_credentials; 2 - user_only
302 0           my $uri = new URI($url);
303 0           my ($u,$p) = parse_credentials($uri);
304 0 0 0       return $url unless defined($p) && length($p);
305 0 0         $uri->userinfo($full ? ($full == 1 ? undef : $u) : sprintf("%s:*****", $u));
    0          
306 0           return $uri->canonical->as_string;
307             }
308             sub set2attr {
309 0     0 1   my $in = shift;
310 0           my $attr = array($in => "set");
311 0           my %attrs;
312 0           foreach (@$attr) {
313 0 0         $attrs{$1} = $2 if $_ =~ /^\s*(\S+)\s+(.+)$/;
314             }
315 0           return {%attrs};
316             }
317              
318              
319             sub _td { # Test of base directory
320 0     0     my $d = shift; # exclude directory
321 0           my $o = shift; # test object
322              
323 0           my @t;
324             my @sd;
325 0           my $ret = 0;
326 0           my ($volume,$dirs,$file) = File::Spec->splitpath( $o );
327 0 0         return 0 unless $dirs;
328 0 0         if (-f $o) {
    0          
329 0           @sd = File::Spec->splitdir(File::Spec->catdir($volume, $dirs));
330             #print join("#",@sd),"\n";
331             } elsif (-d $o) {
332 0           @sd = File::Spec->splitdir($o);
333             } else {
334 0           return 1; # undefined object - skipped!
335             }
336 0           for (@sd) {
337 0           push @t, $_;
338 0 0         if (File::Spec->catdir(@t) eq $d) {
339 0           $ret = 1;
340 0           last;
341             }
342             }
343 0           return $ret;
344             }
345              
346             1;