1b8851fccSafresh1package ExtUtils::Command; 2b8851fccSafresh1 3b8851fccSafresh1use 5.00503; 4b8851fccSafresh1use strict; 5eac174f2Safresh1use warnings; 6b8851fccSafresh1require Exporter; 7*e0680481Safresh1our @ISA = qw(Exporter); 8*e0680481Safresh1our @EXPORT = qw(cp rm_f rm_rf mv cat eqtime mkpath touch test_f test_d chmod 9b8851fccSafresh1 dos2unix); 10*e0680481Safresh1our $VERSION = '7.70'; 1156d68f1eSafresh1$VERSION =~ tr/_//d; 12b8851fccSafresh1 13b8851fccSafresh1my $Is_VMS = $^O eq 'VMS'; 14b8851fccSafresh1my $Is_VMS_mode = $Is_VMS; 15b8851fccSafresh1my $Is_VMS_noefs = $Is_VMS; 16b8851fccSafresh1my $Is_Win32 = $^O eq 'MSWin32'; 17b8851fccSafresh1 18b8851fccSafresh1if( $Is_VMS ) { 19b8851fccSafresh1 my $vms_unix_rpt; 20b8851fccSafresh1 my $vms_efs; 21b8851fccSafresh1 my $vms_case; 22b8851fccSafresh1 23b8851fccSafresh1 if (eval { local $SIG{__DIE__}; 24b8851fccSafresh1 local @INC = @INC; 25b8851fccSafresh1 pop @INC if $INC[-1] eq '.'; 26b8851fccSafresh1 require VMS::Feature; }) { 27b8851fccSafresh1 $vms_unix_rpt = VMS::Feature::current("filename_unix_report"); 28b8851fccSafresh1 $vms_efs = VMS::Feature::current("efs_charset"); 29b8851fccSafresh1 $vms_case = VMS::Feature::current("efs_case_preserve"); 30b8851fccSafresh1 } else { 31b8851fccSafresh1 my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || ''; 32b8851fccSafresh1 my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || ''; 33b8851fccSafresh1 my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || ''; 34b8851fccSafresh1 $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i; 35b8851fccSafresh1 $vms_efs = $efs_charset =~ /^[ET1]/i; 36b8851fccSafresh1 $vms_case = $efs_case =~ /^[ET1]/i; 37b8851fccSafresh1 } 38b8851fccSafresh1 $Is_VMS_mode = 0 if $vms_unix_rpt; 39b8851fccSafresh1 $Is_VMS_noefs = 0 if ($vms_efs); 40b8851fccSafresh1} 41b8851fccSafresh1 42b8851fccSafresh1 43b8851fccSafresh1=head1 NAME 44b8851fccSafresh1 45b8851fccSafresh1ExtUtils::Command - utilities to replace common UNIX commands in Makefiles etc. 46b8851fccSafresh1 47b8851fccSafresh1=head1 SYNOPSIS 48b8851fccSafresh1 49b8851fccSafresh1 perl -MExtUtils::Command -e cat files... > destination 50b8851fccSafresh1 perl -MExtUtils::Command -e mv source... destination 51b8851fccSafresh1 perl -MExtUtils::Command -e cp source... destination 52b8851fccSafresh1 perl -MExtUtils::Command -e touch files... 53b8851fccSafresh1 perl -MExtUtils::Command -e rm_f files... 54b8851fccSafresh1 perl -MExtUtils::Command -e rm_rf directories... 55b8851fccSafresh1 perl -MExtUtils::Command -e mkpath directories... 56b8851fccSafresh1 perl -MExtUtils::Command -e eqtime source destination 57b8851fccSafresh1 perl -MExtUtils::Command -e test_f file 58b8851fccSafresh1 perl -MExtUtils::Command -e test_d directory 59b8851fccSafresh1 perl -MExtUtils::Command -e chmod mode files... 60b8851fccSafresh1 ... 61b8851fccSafresh1 62b8851fccSafresh1=head1 DESCRIPTION 63b8851fccSafresh1 64b8851fccSafresh1The module is used to replace common UNIX commands. In all cases the 65b8851fccSafresh1functions work from @ARGV rather than taking arguments. This makes 66b8851fccSafresh1them easier to deal with in Makefiles. Call them like this: 67b8851fccSafresh1 68b8851fccSafresh1 perl -MExtUtils::Command -e some_command some files to work on 69b8851fccSafresh1 70b8851fccSafresh1and I<NOT> like this: 71b8851fccSafresh1 72b8851fccSafresh1 perl -MExtUtils::Command -e 'some_command qw(some files to work on)' 73b8851fccSafresh1 74b8851fccSafresh1For that use L<Shell::Command>. 75b8851fccSafresh1 76b8851fccSafresh1Filenames with * and ? will be glob expanded. 77b8851fccSafresh1 78b8851fccSafresh1 79b8851fccSafresh1=head2 FUNCTIONS 80b8851fccSafresh1 81b8851fccSafresh1=over 4 82b8851fccSafresh1 83b8851fccSafresh1=cut 84b8851fccSafresh1 85b8851fccSafresh1# VMS uses % instead of ? to mean "one character" 86b8851fccSafresh1my $wild_regex = $Is_VMS ? '*%' : '*?'; 87b8851fccSafresh1sub expand_wildcards 88b8851fccSafresh1{ 89b8851fccSafresh1 @ARGV = map(/[$wild_regex]/o ? glob($_) : $_,@ARGV); 90b8851fccSafresh1} 91b8851fccSafresh1 92b8851fccSafresh1 93b8851fccSafresh1=item cat 94b8851fccSafresh1 95b8851fccSafresh1 cat file ... 96b8851fccSafresh1 97b8851fccSafresh1Concatenates all files mentioned on command line to STDOUT. 98b8851fccSafresh1 99b8851fccSafresh1=cut 100b8851fccSafresh1 101b8851fccSafresh1sub cat () 102b8851fccSafresh1{ 103b8851fccSafresh1 expand_wildcards(); 104b8851fccSafresh1 print while (<>); 105b8851fccSafresh1} 106b8851fccSafresh1 107b8851fccSafresh1=item eqtime 108b8851fccSafresh1 109b8851fccSafresh1 eqtime source destination 110b8851fccSafresh1 111b8851fccSafresh1Sets modified time of destination to that of source. 112b8851fccSafresh1 113b8851fccSafresh1=cut 114b8851fccSafresh1 115b8851fccSafresh1sub eqtime 116b8851fccSafresh1{ 117b8851fccSafresh1 my ($src,$dst) = @ARGV; 118b8851fccSafresh1 local @ARGV = ($dst); touch(); # in case $dst doesn't exist 119b8851fccSafresh1 utime((stat($src))[8,9],$dst); 120b8851fccSafresh1} 121b8851fccSafresh1 122b8851fccSafresh1=item rm_rf 123b8851fccSafresh1 124b8851fccSafresh1 rm_rf files or directories ... 125b8851fccSafresh1 126b8851fccSafresh1Removes files and directories - recursively (even if readonly) 127b8851fccSafresh1 128b8851fccSafresh1=cut 129b8851fccSafresh1 130b8851fccSafresh1sub rm_rf 131b8851fccSafresh1{ 132b8851fccSafresh1 expand_wildcards(); 133b8851fccSafresh1 require File::Path; 134b8851fccSafresh1 File::Path::rmtree([grep -e $_,@ARGV],0,0); 135b8851fccSafresh1} 136b8851fccSafresh1 137b8851fccSafresh1=item rm_f 138b8851fccSafresh1 139b8851fccSafresh1 rm_f file ... 140b8851fccSafresh1 141b8851fccSafresh1Removes files (even if readonly) 142b8851fccSafresh1 143b8851fccSafresh1=cut 144b8851fccSafresh1 145b8851fccSafresh1sub rm_f { 146b8851fccSafresh1 expand_wildcards(); 147b8851fccSafresh1 148b8851fccSafresh1 foreach my $file (@ARGV) { 149b8851fccSafresh1 next unless -f $file; 150b8851fccSafresh1 151b8851fccSafresh1 next if _unlink($file); 152b8851fccSafresh1 153b8851fccSafresh1 chmod(0777, $file); 154b8851fccSafresh1 155b8851fccSafresh1 next if _unlink($file); 156b8851fccSafresh1 157b8851fccSafresh1 require Carp; 158b8851fccSafresh1 Carp::carp("Cannot delete $file: $!"); 159b8851fccSafresh1 } 160b8851fccSafresh1} 161b8851fccSafresh1 162b8851fccSafresh1sub _unlink { 163b8851fccSafresh1 my $files_unlinked = 0; 164b8851fccSafresh1 foreach my $file (@_) { 165b8851fccSafresh1 my $delete_count = 0; 166b8851fccSafresh1 $delete_count++ while unlink $file; 167b8851fccSafresh1 $files_unlinked++ if $delete_count; 168b8851fccSafresh1 } 169b8851fccSafresh1 return $files_unlinked; 170b8851fccSafresh1} 171b8851fccSafresh1 172b8851fccSafresh1 173b8851fccSafresh1=item touch 174b8851fccSafresh1 175b8851fccSafresh1 touch file ... 176b8851fccSafresh1 177b8851fccSafresh1Makes files exist, with current timestamp 178b8851fccSafresh1 179b8851fccSafresh1=cut 180b8851fccSafresh1 181b8851fccSafresh1sub touch { 182b8851fccSafresh1 my $t = time; 183b8851fccSafresh1 expand_wildcards(); 184b8851fccSafresh1 foreach my $file (@ARGV) { 185b8851fccSafresh1 open(FILE,">>$file") || die "Cannot write $file:$!"; 186b8851fccSafresh1 close(FILE); 187b8851fccSafresh1 utime($t,$t,$file); 188b8851fccSafresh1 } 189b8851fccSafresh1} 190b8851fccSafresh1 191b8851fccSafresh1=item mv 192b8851fccSafresh1 193b8851fccSafresh1 mv source_file destination_file 194b8851fccSafresh1 mv source_file source_file destination_dir 195b8851fccSafresh1 196b8851fccSafresh1Moves source to destination. Multiple sources are allowed if 197b8851fccSafresh1destination is an existing directory. 198b8851fccSafresh1 199b8851fccSafresh1Returns true if all moves succeeded, false otherwise. 200b8851fccSafresh1 201b8851fccSafresh1=cut 202b8851fccSafresh1 203b8851fccSafresh1sub mv { 204b8851fccSafresh1 expand_wildcards(); 205b8851fccSafresh1 my @src = @ARGV; 206b8851fccSafresh1 my $dst = pop @src; 207b8851fccSafresh1 208b8851fccSafresh1 if (@src > 1 && ! -d $dst) { 209b8851fccSafresh1 require Carp; 210b8851fccSafresh1 Carp::croak("Too many arguments"); 211b8851fccSafresh1 } 212b8851fccSafresh1 213b8851fccSafresh1 require File::Copy; 214b8851fccSafresh1 my $nok = 0; 215b8851fccSafresh1 foreach my $src (@src) { 216b8851fccSafresh1 $nok ||= !File::Copy::move($src,$dst); 217b8851fccSafresh1 } 218b8851fccSafresh1 return !$nok; 219b8851fccSafresh1} 220b8851fccSafresh1 221b8851fccSafresh1=item cp 222b8851fccSafresh1 223b8851fccSafresh1 cp source_file destination_file 224b8851fccSafresh1 cp source_file source_file destination_dir 225b8851fccSafresh1 226b8851fccSafresh1Copies sources to the destination. Multiple sources are allowed if 227b8851fccSafresh1destination is an existing directory. 228b8851fccSafresh1 229b8851fccSafresh1Returns true if all copies succeeded, false otherwise. 230b8851fccSafresh1 231b8851fccSafresh1=cut 232b8851fccSafresh1 233b8851fccSafresh1sub cp { 234b8851fccSafresh1 expand_wildcards(); 235b8851fccSafresh1 my @src = @ARGV; 236b8851fccSafresh1 my $dst = pop @src; 237b8851fccSafresh1 238b8851fccSafresh1 if (@src > 1 && ! -d $dst) { 239b8851fccSafresh1 require Carp; 240b8851fccSafresh1 Carp::croak("Too many arguments"); 241b8851fccSafresh1 } 242b8851fccSafresh1 243b8851fccSafresh1 require File::Copy; 244b8851fccSafresh1 my $nok = 0; 245b8851fccSafresh1 foreach my $src (@src) { 246b8851fccSafresh1 $nok ||= !File::Copy::copy($src,$dst); 247b8851fccSafresh1 248b8851fccSafresh1 # Win32 does not update the mod time of a copied file, just the 249b8851fccSafresh1 # created time which make does not look at. 250b8851fccSafresh1 utime(time, time, $dst) if $Is_Win32; 251b8851fccSafresh1 } 252b8851fccSafresh1 return $nok; 253b8851fccSafresh1} 254b8851fccSafresh1 255b8851fccSafresh1=item chmod 256b8851fccSafresh1 257b8851fccSafresh1 chmod mode files ... 258b8851fccSafresh1 259b8851fccSafresh1Sets UNIX like permissions 'mode' on all the files. e.g. 0666 260b8851fccSafresh1 261b8851fccSafresh1=cut 262b8851fccSafresh1 263b8851fccSafresh1sub chmod { 264b8851fccSafresh1 local @ARGV = @ARGV; 265b8851fccSafresh1 my $mode = shift(@ARGV); 266b8851fccSafresh1 expand_wildcards(); 267b8851fccSafresh1 268b8851fccSafresh1 if( $Is_VMS_mode && $Is_VMS_noefs) { 269b8851fccSafresh1 require File::Spec; 270b8851fccSafresh1 foreach my $idx (0..$#ARGV) { 271b8851fccSafresh1 my $path = $ARGV[$idx]; 272b8851fccSafresh1 next unless -d $path; 273b8851fccSafresh1 274b8851fccSafresh1 # chmod 0777, [.foo.bar] doesn't work on VMS, you have to do 275b8851fccSafresh1 # chmod 0777, [.foo]bar.dir 276b8851fccSafresh1 my @dirs = File::Spec->splitdir( $path ); 277b8851fccSafresh1 $dirs[-1] .= '.dir'; 278b8851fccSafresh1 $path = File::Spec->catfile(@dirs); 279b8851fccSafresh1 280b8851fccSafresh1 $ARGV[$idx] = $path; 281b8851fccSafresh1 } 282b8851fccSafresh1 } 283b8851fccSafresh1 284b8851fccSafresh1 chmod(oct $mode,@ARGV) || die "Cannot chmod ".join(' ',$mode,@ARGV).":$!"; 285b8851fccSafresh1} 286b8851fccSafresh1 287b8851fccSafresh1=item mkpath 288b8851fccSafresh1 289b8851fccSafresh1 mkpath directory ... 290b8851fccSafresh1 291b8851fccSafresh1Creates directories, including any parent directories. 292b8851fccSafresh1 293b8851fccSafresh1=cut 294b8851fccSafresh1 295b8851fccSafresh1sub mkpath 296b8851fccSafresh1{ 297b8851fccSafresh1 expand_wildcards(); 298b8851fccSafresh1 require File::Path; 299b8851fccSafresh1 File::Path::mkpath([@ARGV],0,0777); 300b8851fccSafresh1} 301b8851fccSafresh1 302b8851fccSafresh1=item test_f 303b8851fccSafresh1 304b8851fccSafresh1 test_f file 305b8851fccSafresh1 306b8851fccSafresh1Tests if a file exists. I<Exits> with 0 if it does, 1 if it does not (ie. 307b8851fccSafresh1shell's idea of true and false). 308b8851fccSafresh1 309b8851fccSafresh1=cut 310b8851fccSafresh1 311b8851fccSafresh1sub test_f 312b8851fccSafresh1{ 313b8851fccSafresh1 exit(-f $ARGV[0] ? 0 : 1); 314b8851fccSafresh1} 315b8851fccSafresh1 316b8851fccSafresh1=item test_d 317b8851fccSafresh1 318b8851fccSafresh1 test_d directory 319b8851fccSafresh1 320b8851fccSafresh1Tests if a directory exists. I<Exits> with 0 if it does, 1 if it does 321b8851fccSafresh1not (ie. shell's idea of true and false). 322b8851fccSafresh1 323b8851fccSafresh1=cut 324b8851fccSafresh1 325b8851fccSafresh1sub test_d 326b8851fccSafresh1{ 327b8851fccSafresh1 exit(-d $ARGV[0] ? 0 : 1); 328b8851fccSafresh1} 329b8851fccSafresh1 330b8851fccSafresh1=item dos2unix 331b8851fccSafresh1 332b8851fccSafresh1 dos2unix files or dirs ... 333b8851fccSafresh1 334b8851fccSafresh1Converts DOS and OS/2 linefeeds to Unix style recursively. 335b8851fccSafresh1 336b8851fccSafresh1=cut 337b8851fccSafresh1 338b8851fccSafresh1sub dos2unix { 339b8851fccSafresh1 require File::Find; 340b8851fccSafresh1 File::Find::find(sub { 341b8851fccSafresh1 return if -d; 342b8851fccSafresh1 return unless -w _; 343b8851fccSafresh1 return unless -r _; 344b8851fccSafresh1 return if -B _; 345b8851fccSafresh1 346b8851fccSafresh1 local $\; 347b8851fccSafresh1 348b8851fccSafresh1 my $orig = $_; 349b8851fccSafresh1 my $temp = '.dos2unix_tmp'; 350b8851fccSafresh1 open ORIG, $_ or do { warn "dos2unix can't open $_: $!"; return }; 351b8851fccSafresh1 open TEMP, ">$temp" or 352b8851fccSafresh1 do { warn "dos2unix can't create .dos2unix_tmp: $!"; return }; 3535759b3d2Safresh1 binmode ORIG; binmode TEMP; 354b8851fccSafresh1 while (my $line = <ORIG>) { 355b8851fccSafresh1 $line =~ s/\015\012/\012/g; 356b8851fccSafresh1 print TEMP $line; 357b8851fccSafresh1 } 358b8851fccSafresh1 close ORIG; 359b8851fccSafresh1 close TEMP; 360b8851fccSafresh1 rename $temp, $orig; 361b8851fccSafresh1 362b8851fccSafresh1 }, @ARGV); 363b8851fccSafresh1} 364b8851fccSafresh1 365b8851fccSafresh1=back 366b8851fccSafresh1 367b8851fccSafresh1=head1 SEE ALSO 368b8851fccSafresh1 369b8851fccSafresh1Shell::Command which is these same functions but take arguments normally. 370b8851fccSafresh1 371b8851fccSafresh1 372b8851fccSafresh1=head1 AUTHOR 373b8851fccSafresh1 374b8851fccSafresh1Nick Ing-Simmons C<ni-s@cpan.org> 375b8851fccSafresh1 376b8851fccSafresh1Maintained by Michael G Schwern C<schwern@pobox.com> within the 377b8851fccSafresh1ExtUtils-MakeMaker package and, as a separate CPAN package, by 378b8851fccSafresh1Randy Kobes C<r.kobes@uwinnipeg.ca>. 379b8851fccSafresh1 380b8851fccSafresh1=cut 381b8851fccSafresh1 382