File Coverage

/root/.cpan/build/PerlPowerTools-1.053-0/bin/cp
Criterion Covered Total %
statement 55 88 62.5
branch 10 32 31.2
condition 1 9 11.1
subroutine 12 15 80.0
pod n/a
total 78 144 54.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             =begin metadata
4              
5             Name: cp
6             Description: copy files and/or directories
7             Author: brian d foy, bdfoy@cpan.org
8             License: artistic2
9              
10             =end metadata
11              
12             =cut
13              
14             package PerlPowerTools::cp;
15              
16 2     2   9425 use strict;
  2         4  
  2         97  
17              
18 2     2   11 use Config;
  2         4  
  2         142  
19 2     2   1546 use ExtUtils::MakeMaker qw(prompt);
  2         264912  
  2         151  
20 2     2   15 use File::Basename qw(basename);
  2         5  
  2         84  
21 2     2   782 use File::Spec::Functions qw(catfile);
  2         1600  
  2         203  
22              
23 2 50       150505 exit( run( {}, @ARGV) ) unless caller;
24              
25             BEGIN {
26 2     2   6 $PerlPowerTools::cp::error_fh = \*STDERR;
27 2         92 $PerlPowerTools::cp::output_fh = \*STDOUT;
28             }
29              
30 0     0   0 sub error_fh { $PerlPowerTools::cp::error_fh }
31 0     0   0 sub output_fh { $PerlPowerTools::cp::output_fh }
32              
33 2     2   12 use constant EX_SUCCESS => 0;
  2         3  
  2         153  
34 2     2   11 use constant EX_FAILURE => 1;
  2         6  
  2         141  
35 2     2   11 use constant EX_USAGE => 2;
  2         2  
  2         4008  
36              
37             sub run {
38 2     2   12 my( $settings, @args ) = @_;
39 2 50       9 $settings = {} unless defined $settings;
40              
41 2 50       8 $PerlPowerTools::cp::error_fh = $settings->{error_fh} if exists $settings->{error_fh};
42 2 50       6 $PerlPowerTools::cp::output_fh = $settings->{output_fh} if exists $settings->{output_fh};
43              
44 2         9 my( $opts, @files) = process_arguments(@args);
45 2         15 my $destination = pop @files;
46              
47 2 50       19 return EX_USAGE unless defined $opts;
48 2 50       6 unless (@files) {
49 0         0 warn "$0: missing file operand\n";
50 0         0 usage();
51 0         0 return EX_USAGE;
52             }
53              
54 2         7 my @unix_like = qw(darwin freebsd linux);
55 2 50 33     8 if( grep { $^O eq $_ } @unix_like and in_path('cp') ) {
  6         27  
56             # Although File::Copy seems like it should do the right thing,
57             # it doesn't.
58 2         10 my @command = 'cp';
59 2         7 push @command, map { "-$_" } grep { $opts->{$_} } qw(i f p v );
  0         0  
  8         20  
60 2         7 push @command, '--', @files, $destination;
61              
62 2         4 my $rc = system { $command[0] } @command;
  2         15234  
63 2         0 return $rc >> 8;
64             }
65             else {
66 0         0 require File::Copy;
67 0         0 my $err = 0;
68 0         0 foreach my $source (@files) {
69 0 0       0 if (-d $source) {
70 0         0 print { error_fh() } "$0: '$source' is a directory (not copied)\n";
  0         0  
71 0         0 $err = 1;
72 0         0 next;
73             }
74 0         0 my $catdst = $destination;
75 0 0       0 if( -d $destination ) {
76 0         0 $catdst = catfile( $destination, basename($source) )
77             }
78              
79 0 0       0 print { output_fh() } "$source -> $catdst\n" if $opts->{v};
  0         0  
80 0 0 0     0 if( -e $catdst and $opts->{i} and ! $opts->{f} ) {
      0        
81 0         0 my $answer = prompt( "overwrite $catdst? (y/n [n])", 'n' );
82 0 0       0 next unless $answer =~ m/\A\s*y/i;
83             }
84 0 0       0 if (File::Copy::copy($source, $catdst) == 0) {
85 0         0 print { error_fh() } "$0: $source -> $catdst: copy failed: $!\n";
  0         0  
86 0         0 $err = 1;
87             }
88             }
89 0 0       0 return $err ? EX_FAILURE : EX_SUCCESS;
90             }
91              
92 0         0 return EX_FAILURE;
93             }
94              
95             sub in_path {
96 2     2   8 my( $command ) = @_;
97 2         63 foreach my $dir ( split /$Config{path_sep}/, $ENV{PATH} ) {
98 14         52 my $path = catfile( $dir, $command );
99 14 100       306 return 1 if -x $path;
100             }
101 0         0 return 0;
102             }
103              
104             sub process_arguments {
105 2     2   6 my @args = @_;
106 2         4 my %opts;
107              
108 2         1342 require Getopt::Long;
109 2         31721 Getopt::Long::Configure('bundling');
110             Getopt::Long::GetOptionsFromArray(
111             \@args,
112             'f' => \$opts{'f'},
113             'i' => \$opts{'i'},
114             'n' => \$opts{'n'},
115             'p' => \$opts{'p'},
116             'v' => \$opts{'v'},
117 2 50       82 ) or do {
118 0         0 usage();
119 0         0 return;
120             };
121 2         1569 return ( \%opts, @args )
122             }
123              
124             sub usage {
125 0     0     require Pod::Usage;
126 0           Pod::Usage::pod2usage({ -exitval => 'NOEXIT', -verbose => 0 });
127             }
128              
129             __PACKAGE__;
130              
131             =pod
132              
133             =encoding utf8
134              
135             =head1 NAME
136              
137             cp - copy files and/or directories
138              
139             =head1 SYNOPSIS
140              
141             % cp [-fipv] source_file target_file
142             % cp [-fipv] source... target_dir
143              
144             =head1 DESCRIPTION
145              
146             The cp utility copies the source files/directories to the target. If the
147             target is a file you may only specify one file as the source. cp will not
148             copy a file onto itself.
149              
150             =head2 OPTIONS
151              
152             =over 4
153              
154             =item * B<-f> - force copy if possible (DEFAULT)
155              
156             =item * B<-i> - prompt for confirmation whenever the copy would overwrite an existing target.
157              
158             =item * B<-p> - preserve source file attributes (like modDate) as much as possible onto the target.
159              
160             =item * B<-v> - verbose. Echo "cp source target" before copy is done.
161              
162             =back
163              
164             Specifying both B<-f> and B<-i> options is not considered an
165             error. The B<-f> option will override the B<-i> option.
166              
167             =head1 BUGS
168              
169             B has no known bugs, but be aware that the current copy mode
170             is binary mode.
171              
172             =head1 EXIT STATUS
173              
174             =over 4
175              
176             =item * 0 - All sources were copied successfully.
177              
178             =item * 1 - There was error
179              
180             =back
181              
182             =head1 AUTHOR
183              
184             brian d foy, Eschumacks@att.netE
185              
186             =head1 COPYRIGHT and LICENSE
187              
188             Copyright © 2023 brian d foy. All rights reserved.
189              
190             You may use this program under the terms of the Artistic License 2.0.
191              
192             =cut
193