File Coverage

blib/lib/File/PerlMove.pm
Criterion Covered Total %
statement 70 91 76.9
branch 32 58 55.1
condition 9 19 47.3
subroutine 10 12 83.3
pod 0 3 0.0
total 121 183 66.1


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package File::PerlMove;
4              
5             # Author : Johan Vromans
6             # Created On : Tue Sep 15 15:59:04 1992
7             # Last Modified By: Johan Vromans
8             # Last Modified On: Tue Dec 15 14:59:21 2020
9             # Update Count : 223
10             # Status : Unknown, Use with caution!
11              
12             ################ Common stuff ################
13              
14             our $VERSION = "2.01";
15              
16 4     4   227323 use strict;
  4         31  
  4         97  
17 4     4   29 use warnings;
  4         5  
  4         78  
18 4     4   17 use Carp;
  4         6  
  4         234  
19 4     4   23 use File::Basename;
  4         6  
  4         418  
20 4     4   23 use File::Path;
  4         5  
  4         227  
21 4     4   1663 use parent qw(Exporter);
  4         970  
  4         18  
22              
23             our @EXPORT = qw( pmv );
24              
25             sub move {
26 0     0 0 0 my $transform = shift;
27 0         0 my $filelist = shift;
28 0   0     0 my $options = shift || {};
29 0         0 pmv( $transform, $filelist, { %$options, legacy => 1 } );
30             }
31              
32             sub pmv {
33 10     10 0 8128 my $transform = shift;
34 10         16 my $filelist = shift;
35 10   100     33 my $options = shift || {};
36 10         16 my $result = 0;
37              
38 10 50 33     44 croak("Usage: ", __PACKAGE__, "::move(" .
39             "operation, [ file names ], { options })")
40             unless defined $transform && defined $filelist;
41              
42             # For those who misunderstood the docs.
43 10   33     45 $options->{showonly} ||= delete $options->{'dry-run'};
44 10   66     37 $options->{createdirs} ||= delete $options->{'create-dirs'};
45              
46             # Create transformer.
47 10 100       30 $transform = build_sub( $transform, $options )
48             unless ref($transform) eq 'CODE';
49              
50             # Process arguments.
51 10 50       56 @$filelist = reverse(@$filelist) if $options->{reverse};
52 10         22 foreach ( @$filelist ) {
53             # Save the name.
54 10         17 my $old = $_;
55              
56             # Perform the transformation.
57 10         11 my $new;
58 10 50       22 if ( $options->{legacy}) {
59             # Legacy operates on $_.
60 0         0 $transform->();
61 0         0 $new = $_;
62             }
63             else {
64 10         127 $new = $transform->($_);
65             }
66              
67             # Anything changed?
68 10 50       57 unless ( $old eq $new ) {
69              
70             # Create directories.
71 10 100       25 if ( $options->{createdirs} ) {
72 1         63 my $dir = dirname($new);
73 1 50       12 unless ( -d $dir ) {
74 1 50       5 if ( $options->{showonly} ) {
75 0         0 warn("[Would create: $dir]\n");
76             }
77             else {
78 1         120 mkpath($dir, $options->{verbose}, 0777);
79             }
80             }
81             }
82              
83             # Dry run.
84 10 50 33     43 if ( $options->{verbose} || $options->{showonly} ) {
85 0         0 warn("$old => $new\n");
86 0 0       0 next if $options->{showonly};
87             }
88              
89             # Check for overwriting target.
90 10 100 66     184 if ( ! $options->{overwrite} && -e $new ) {
91 2         25 warn("$new: exists\n");
92 2         15 next;
93             }
94              
95             # Perform.
96 8         20 my $res = -1;
97 8 100       33 if ( $options->{symlink} ) {
    100          
98 1         30 $res = symlink($old, $new);
99             }
100             elsif ( $options->{link} ) {
101 1         27 $res = link($old, $new);
102             }
103             else {
104 6         141 $res = rename($old, $new);
105             }
106 8 100       36 if ( $res == 1 ) {
107 7         20 $result++;
108             }
109             else {
110             # Force error numbers (for locale independency).
111             warn($options->{errno}
112 1 50       26 ? "$old: ".(0+$!)."\n"
113             : "$old: $!\n");
114             }
115             }
116             }
117              
118 10         110 $result;
119             }
120              
121             sub build_sub {
122 9     9 0 19 my ( $cmd, $options ) = @_;
123              
124             # If it is a verb, try extensions and builtins.
125             # foo File::PerlMove::foo => &File::PerlMove::foo::foo
126             # foo=bar File::PerlMove::foo => &File::PerlMove::foo::bar
127             # xx::foo xx::foo => &xx::foo::foo
128             # xx::foo=bar xx::foo => &xx::foo::bar
129 9 100       60 if ( $cmd =~ /^((?:\w|::)+)(?:=(\w+))?$/ ) {
130 2         4 my $pkg = $1;
131 2         4 my $sub = $2;
132 2 50       5 if ( !defined($sub) ) {
133 2 50       4 if ( $pkg =~ /^(.*)::(\w+)$/ ) {
134 0         0 $sub = $2;
135             }
136             else {
137 2         4 $sub = $pkg;
138             }
139             }
140 2 50       6 $pkg = __PACKAGE__."::".$pkg unless $pkg =~ /::/;
141 2 50       6 warn("OP: $pkg => $sub\n") if $options->{trace};
142              
143             # Extensions.
144 2 50       89 if ( eval "require $pkg" ) {
    50          
145 0 0       0 if ( my $op = $pkg->can($sub) ) {
146 0 0       0 return "$pkg => $sub" if $options->{testing};
147 0         0 return $op;
148             }
149             else {
150 0         0 croak("$pkg does not provide a subroutine $sub");
151             }
152             }
153             # Builtins.
154             elsif ( my $op = (__PACKAGE__."::BuiltIn")->can($cmd) ) {
155 2 50       7 return __PACKAGE__."::BuiltIn => $cmd" if $options->{testing};
156 2         10 return $op;
157             }
158 0         0 croak("No such operation: $cmd");
159             }
160              
161             # Recode.
162 7 50       21 if ( $cmd =~ /^:(.+):(.+):$/ ) {
163 0 0       0 return 'Encode::from_to($_,"'.$1.'","'.$2.'")' if $options->{testing};
164 0         0 require Encode;
165 0         0 $cmd = 'Encode::from_to($_,"'.$1.'","'.$2.'")';
166             }
167              
168             # Hopefully a regex. Build subroutine.
169 7 50       20 return "sub { \$_ = \$_[0]; $cmd; \$_ }" if $options->{testing};
170 7         579 my $op = eval "sub { \$_ = \$_[0]; $cmd; \$_ }";
171 7 50       27 if ( $@ ) {
172 0         0 $@ =~ s/ at \(eval.*/./;
173 0         0 croak($@);
174             }
175              
176 7         13 return $op;
177             }
178              
179             package File::PerlMove::BuiltIn;
180              
181 1     1   3 sub lc { CORE::lc($_[0]) }
182 1     1   3 sub uc { CORE::uc($_[0]) }
183 0     0     sub ucfirst { CORE::ucfirst($_[0]) }
184              
185             1;
186              
187             __END__