File Coverage

blib/lib/Module/Rename.pm
Criterion Covered Total %
statement 131 132 99.2
branch 32 36 88.8
condition 18 18 100.0
subroutine 18 18 100.0
pod 2 7 28.5
total 201 211 95.2


line stmt bran cond sub pod time code
1             ###########################################
2             package Module::Rename;
3             ###########################################
4              
5 2     2   299846 use strict;
  2         5  
  2         63  
6 2     2   13 use warnings;
  2         4  
  2         65  
7 2     2   9 use File::Find;
  2         8  
  2         104  
8 2     2   10 use File::Basename;
  2         3  
  2         118  
9 2     2   9 use File::Spec qw( splitdir );
  2         4  
  2         39  
10 2     2   10 use Sysadm::Install qw(:all);
  2         3  
  2         22  
11 2     2   694 use Log::Log4perl qw(:easy);
  2         4  
  2         17  
12 2     2   1263 use File::Spec::Functions qw( abs2rel splitdir );
  2         3  
  2         3192  
13              
14             our $VERSION = "0.04";
15              
16             ###########################################
17             sub new {
18             ###########################################
19 2     2 1 243234 my($class, %options) = @_;
20              
21 2         39 my $self = {
22             name_old => undef,
23             name_new => undef,
24             dir_exclude => ['blib'],
25             dir_ignore => ['CVS'],
26             wipe_empty_subdirs => 0,
27             use_git => 0,
28             %options,
29             };
30              
31 2 100       26 if( $self->{use_git} ) {
32 1         16 $self->{ git_bin } = bin_find( "git" );
33 1 50       277 if( !defined $self->{ git_bin } ) {
34 0         0 die "No git executable found";
35             }
36 1         3 push @{ $self->{dir_exclude} }, ".git";
  1         7  
37             }
38              
39 2         5 $self->{dir_exclude_hash} = { map { $_ => 1 } @{$self->{dir_exclude}} };
  3         19  
  2         7  
40 2         8 $self->{dir_ignore_hash} = { map { $_ => 1 } @{$self->{dir_ignore}} };
  2         14  
  2         5  
41              
42 2         18 ($self->{look_for} = $self->{name_old}) =~ s#::#/#g;
43 2         13 ($self->{replace_by} = $self->{name_new}) =~ s#::#/#g;
44              
45 2         19 ($self->{pmfile} = $self->{name_old}) =~ s#.*::##g;
46 2         5 $self->{pmfile} .= ".pm";
47              
48 2         11 ($self->{new_pmfile} = $self->{name_new}) =~ s#.*::##g;
49 2         7 $self->{new_pmfile} .= ".pm";
50              
51 2         16 bless $self, $class;
52             }
53              
54             ###########################################
55             sub longest_common_path {
56             ###########################################
57 2     2 0 6 my( $self, $file1, $file2 ) = @_;
58              
59 2         4 my @common = ();
60              
61 2         71 my @dirs1 = splitdir( dirname $file1 );
62 2         84 my @dirs2 = splitdir( dirname $file2 );
63              
64 2         21 for my $dir1_part ( @dirs1 ) {
65 6         11 my $dir2_part = shift @dirs2;
66 6 100       15 if( $dir1_part eq $dir2_part ) {
67 5         11 push @common, $dir1_part;
68             } else {
69 1         6 last;
70             }
71             }
72              
73 2         60 return File::Spec->catfile( @common );
74             }
75              
76             ###########################################
77             sub move {
78             ###########################################
79 8     8 0 17 my($self, $old_path, $new_path) = @_;
80              
81 8 100       27 if( $old_path ne $new_path ) {
82 6 100 100     92 if ($self->{use_git} and !-d $old_path) {
83             # make sure we launch the git command inside the git workspace
84 2         11 my $common = $self->longest_common_path( $old_path, $new_path );
85 2         13 cd $common;
86 2         102 tap("git", "mv",
87             abs2rel( $old_path, $common ),
88             abs2rel( $new_path, $common ),
89             );
90 2         27048 cdback;
91             } else {
92 4         32 mv $old_path, $new_path;
93             }
94             }
95             }
96              
97             ###########################################
98             sub find_and_rename {
99             ###########################################
100 2     2 1 13 my($self, $start_dir) = @_;
101              
102 2         7 my @files = ();
103 2         8 my %empty_subdirs = ();
104              
105             find(sub {
106 28 100 100 28   289945 if(-d and $self->dir_empty($_)) {
107 1         5 INFO "$File::Find::name is an empty subdir";
108 1         10 $empty_subdirs{$File::Find::name}++;
109             }
110 28 100 100     397 if(-d and exists $self->{dir_exclude_hash}->{$_}) {
111 1         3 $File::Find::prune = 1;
112 1         18 return;
113             }
114 27 100       8454 return unless -f $_;
115 15 100 100     189 push @files, $File::Find::name if
116             $File::Find::name =~ /$self->{look_for}/ or
117             $_ eq $self->{pmfile};
118 15         66 $self->file_process($_, $File::Find::name);
119 2         270 }, $start_dir);
120            
121 2         885 for my $file (@files) {
122              
123 4         317 my $newfile = $file;
124              
125 4 100       87 if($file =~ /$self->{look_for}/) {
126 2         47 $newfile =~ s/$self->{look_for}/$self->{replace_by}/;
127             } else {
128             # We found a module file outside the regular
129             # dir structure, just replace it within this directory
130 2         49 $newfile =~ s/$self->{pmfile}/$self->{new_pmfile}/;
131             }
132              
133 4         40 INFO "mv $file $newfile";
134 4         357 my $dir = dirname($newfile);
135 4 100       106 mkd $dir unless -d $dir;
136 4         467 $self->move($file, $newfile);
137             }
138              
139 2         260 (my $dashed_look_for = $self->{name_old}) =~ s#::#-#g;
140 2         18 (my $dashed_replace_by = $self->{name_new}) =~ s#::#-#g;
141              
142             # Rename any top directory files like Foo-Bar-0.01
143 2         12 my @rename_candidates = ($start_dir);
144             find(sub {
145 66 100   66   2644 if(/$dashed_look_for/) {
146 2         243 push @rename_candidates, $File::Find::name;
147             }
148 2         245 }, $start_dir);
149 2         12 for my $item (@rename_candidates) {
150 4         42 (my $newitem = $item) =~ s/$dashed_look_for/$dashed_replace_by/;
151 4         15 $self->move($item, $newitem);
152             }
153              
154             # Even the start_dir could have to be modified.
155 2         315 $start_dir =~ s/$dashed_look_for/$dashed_replace_by/;
156              
157             # Update empty_subdirs with the latest name changes
158 2         14 %empty_subdirs = map { s/$dashed_look_for/$dashed_replace_by/; $_; }
  2         11  
  2         9  
159             %empty_subdirs;
160              
161 2 50       15 if( $self->{wipe_empty_subdirs} ) {
162 2         8 my @dirs = ();
163             # Delete all empty dirs
164             find(sub {
165 30 100   30   104 if( exists $self->{dir_exclude_hash}->{$_} ) {
166 1         3 $File::Find::prune = 1;
167             }
168              
169 30 100 100     729 if(-d and $self->dir_empty($_) and
      100        
170             ! exists $empty_subdirs{$File::Find::name}
171             ) {
172 2         21 WARN "$File::Find::name is empty and can go away";
173 2         161 push @dirs, $File::Find::name;
174             }
175 2         113 }, $start_dir);
176 2         14 for my $dir ( @dirs ) {
177 2         16 rmf $dir;
178             }
179             }
180             }
181              
182             ###########################################
183             sub dir_empty {
184             ###########################################
185 28     28 0 57 my($self, $dir) = @_;
186              
187 28 50       552 opendir DIR, $dir or LOGDIE "Cannot open dir $dir";
188 28 100       470 my @items = grep { $_ ne "." and $_ ne ".." } readdir DIR;
  128         558  
189 28         307 closedir DIR;
190              
191 28         111 @items = grep { ! exists $self->{dir_ignore_hash}->{$_} } @items;
  72         219  
192            
193 28         1022 return ! scalar @items;
194             }
195              
196             ###########################################
197             sub file_process {
198             ###########################################
199 15     15 0 40 my($self, $file, $path) = @_;
200              
201 15         28 my $out = "";
202              
203 15 50       549 open FILE, "<$file" or LOGDIE "Can't open $file ($!)";
204 15         255 while() {
205 358         1170 DEBUG "Looking for /$self->{name_old}/";
206 358         2806 s/($self->{name_old})\b/$self->rep($1,$self->{name_new})/ge;
  48         143  
207 358         1283 DEBUG "Looking for /$self->{look_for}/";
208 358         2645 s/($self->{look_for})\b/$self->rep($1,$self->{replace_by})/ge;
  4         16  
209 358         1292 $out .= $_;
210             }
211 15         194 close FILE;
212              
213 15         70 blurt $out, $file;
214             }
215              
216             ###########################################
217             sub rep {
218             ###########################################
219 52     52 0 113 my($self, $found, $replace) = @_;
220              
221 52         275 INFO "$File::Find::name ($.): $found => $replace";
222 52         432 return $replace;
223             }
224              
225             1;
226              
227             __END__