File Coverage

blib/lib/File/Find/ProjectCycleMigration.pm
Criterion Covered Total %
statement 24 191 12.5
branch 0 62 0.0
condition 0 8 0.0
subroutine 8 15 53.3
pod 0 6 0.0
total 32 282 11.3


line stmt bran cond sub pod time code
1             package File::Find::ProjectCycleMigration;
2            
3 1     1   26096 use 5.008004;
  1         4  
  1         42  
4 1     1   7 use strict;
  1         2  
  1         172  
5 1     1   8 use File::Find;
  1         6  
  1         96  
6 1     1   6 use File::Path;
  1         1  
  1         62  
7 1     1   1086 use File::Copy;
  1         6319  
  1         93  
8 1     1   10 use File::Spec;
  1         2  
  1         25  
9 1     1   1351 use Data::Dumper;
  1         9235  
  1         102  
10 1     1   984 use Time::Local;
  1         2036  
  1         3324  
11            
12             require Exporter;
13            
14             our @ISA = qw(Exporter);
15             our @EXPORT = qw(FindReplace);
16             our $VERSION = '0.01';
17            
18             sub FindReplace{
19 0     0 0   my $config = shift;
20 0           my ($cycle_year,$srcdir) = ($config->{year}, $config->{srcdir});
21 0 0 0       unless(($cycle_year =~/^\d\d\d\d$/) || (-d $srcdir)){
22 0           separator(80,'*');
23 0 0         unless(($cycle_year =~/^\d\d\d\d$/))
24             {
25 0           textFormat(80, "Please enter correct year the given year must be a 4 digit numeric number.\n");
26             }
27 0 0         unless(-d $srcdir){
28 0           textFormat(80,"The given path does not exist please give absolute path.");
29             }
30 0           separator(80,'*');
31 0           die &Usage;
32             }
33 0           my $nextyear = $cycle_year + 1;
34            
35             # The directory to be search on.
36 0           my @directories = File::Spec->splitdir($srcdir);
37 0           my $lastpath = pop @directories; # Get the last directory to be search on
38 0 0         $lastpath = pop @directories if $lastpath eq ''; # If the user gave a / at end of the path then we need to pop twice to skip the ''
39            
40             # Creating the absolute path for the directory to be search on.
41 0           my $folderPath = File::Spec->catdir( @directories, $lastpath );
42            
43             # Creeating the backup directory .
44 0           my $backupFolderPath = File::Spec->catdir( @directories, $lastpath . '_bkp' );
45 0           my $logFilePath = File::Spec->catdir( @directories, $lastpath . '_log' );
46            
47 0           my $grepregex = '[a-zA-Z]+' . $cycle_year . '[^a-zA-Z0-9\_\,]'; #Creating a regex for searching the pattern ie. the year (we can customized it as per the requirement)
48 0           my $grepoutput = `egrep -rhn '$grepregex' $folderPath`; # egrep should be quicker than going file by file and looking for patterns in file using perl only.
49 0           my @op = ( $grepoutput =~ /([a-zA-Z]{4,}$cycle_year)[\/\:-]/g ); # We got the patterns that look like stuff we need to replace along with stupid stuff that egrep tries to churn out.
50 0           my %findReplaceH;
51 0           foreach my $string (@op) { # We build a hash to make things easier and removes the duplicate keys ie. search pattern.
52 0           my $replacementstring = $string;
53 0           $replacementstring =~ s/$cycle_year/$nextyear/;
54 0 0         $findReplaceH{$string} = $replacementstring if ( $string =~ /[a-zA-Z]{4,}$cycle_year/ ); # Replace when there are at least 4 more alphanumeric char associated with year.
55             }
56 0           $findReplaceH{$cycle_year} = $nextyear;
57 0 0         mkdir $logFilePath unless(-e $logFilePath);
58            
59 0           my $logFile = "$logFilePath/FindReplace.log";
60 0 0         open( FILE, ">>$logFile" ) || die "cann't open the $!\n";
61 0           my ( $seconds, $minutes, $hours, $day_of_month, $month, $year, $wday, $yday, $isdst ) = gmtime(time);
62 0           $year = $year + 1900;
63 0           $month = $month + 1;
64 0           my $date_string = "$hours:$minutes:$seconds - $day_of_month/$month/$year";
65 0           print FILE "Here we are going to keep logs - TIME : $date_string\n";
66 0           close FILE;
67            
68 0           my $input;
69 0   0       while ((lc($input) ne 'yes' ) && ( scalar(keys%findReplaceH))) {
70 0           separator(80,'*');
71 0           textFormat(80, "Replacement List-");print "\n";
  0            
72 0           textFormat(80, "Right side values are the possible replacement of Left side pattern(given year associated with some alphanumeric characters) find in the directory and sub dir-ectory So possible replacements are-");
73 0           print "\n";
74 0           while(my($key,$val)=(each %findReplaceH)){
75 0           printf ("%35s",$key); print " => " ; printf("%-50s", $val); print "\n" ;
  0            
  0            
  0            
76             }
77 0           separator(80,'*');
78 0           textFormat(150, "Current Config Settings-");print "\n";
  0            
79 0           textFormat(80, "'Current Directory' is the directory where script starts search operation for replacement also script automatically backs up the current code in 'Back-up Dir-ectory' and for logs it creates a 'Log Directory' at one level above the 'Current Directory'");
80 0           print "\n";
81 0           textFormat(150, "Current Directory : $folderPath");
82 0           textFormat(150, "Back-up Directory : $backupFolderPath");
83 0           textFormat(150, "Log Directory \t : $logFile");
84 0           separator(80,'*');
85 0           textFormat(80, "README-");
86 0           textFormat(80,"i. If you want to proceed with above Replacement List/Current Config Settings then type YES otherwise NO to quit ...");
87 0           textFormat(80,"ii. If you want to remove any key => value pair from Replacement List then type the key(Case Sensitive) on terminal. e.g. type key name (left side element) 'foo2011' to remove key-value pair from 'Replacement List'- 'foo2011 => foo2012'");
88 0           print "\t";
89 0           $input = ;
90 0           $input =~ s/^\s+|\s+$//g;
91            
92 0 0         if ( $input =~ /^yes$/i ) {
    0          
93 0           textFormat(80,"Here we go with current Replacement List/Config Settings...");
94             }
95             elsif ( $input =~ /^no$/i ) {
96 0           textFormat(80,"Please check your Current Config Settings in the script.");
97 0           separator(80, '*');
98 0           exit;
99             }
100             else{
101 0           $input =~ s/^\s|\s+$//g;
102 0 0         unless(grep $_ eq $input, keys%findReplaceH){
103 0           textFormat(80,"Please pass only YES/NO option or a valid key name from Replacement List to remove key-value pair from search result.");
104             }
105 0           delete( $findReplaceH{$input} );
106             }
107             }
108 0 0         if(scalar(keys%findReplaceH) == 0){
109 0           textFormat(80,"No search result found for the given year.");
110 0           separator(80, '*');
111 0           exit;
112             }
113            
114             # This closure will rename all directory recursively as per given in hash keys/values
115             finddepth(
116             sub {
117 0 0   0     return unless -d;
118 0 0 0       return if ( $_ eq '.' || $_ eq '..' );
119 0 0         return if ( $_ =~ /.svn|\.svn/ );
120 0           my $new = $_;
121 0           foreach my $key1 ( keys %findReplaceH ) {
122 0           my $pattern = quotemeta($key1);
123 0 0         if ( $new =~ /$pattern/ ) {
124 0           $new =~ s/$pattern/$findReplaceH{$key1}/;
125             }
126             }
127 0 0         if ( $_ eq $new ) {
128 0           return;
129             }
130 0           my $currentDir = $File::Find::dir;
131 0           $currentDir .= "/" . $_;
132 0           my $renamedDir = $File::Find::dir;
133 0           $renamedDir .= "/" . $new;
134            
135 0 0         rename $_, $new or warn "Error while renaming $_ to $new in $File::Find::dir: $!";
136 0 0         open( FILE, ">>$logFile" ) || die "cann't open the $!\n";
137 0           print FILE "Current Directory: $currentDir :: Renamed Directory: $renamedDir\n";
138 0           close FILE;
139 0           }, $folderPath
140             );
141            
142             # $useRegexQ has values 1 or 0. If 1, interprets the pairs in %findReplaceH to be regex.
143 0           my $useRegexQ = 0;
144 0           $folderPath =~ s/\/$//;
145 0           $backupFolderPath =~ s/\/$//;
146 0           $folderPath =~ m/\/(\w+)$/;
147 0           my $previousDir = $`;
148 0           my $lastDir = $1;
149 0           my $backupRoot = $backupFolderPath . '/' . $1;
150            
151 0           my $refchangedFiles = [];
152 0           my $totalFileChangedCount = 0;
153            
154             sub fileFilterQ ($) {
155 0     0 0   my $fileName = $_[0];
156 0 0         next if ( $fileName =~ /(svn|\.svn)/ig );
157            
158 0 0         if ( -f $fileName ) {
159             #print "processing files: $fileName\n";
160 0           return 1;
161             }
162             }
163            
164             # go through each file, accumulate a hash.
165             sub processFile {
166 0     0 0   my $currentFile = $File::Find::name;
167 0           my $currentDir = $File::Find::dir;
168 0           my $previousDir = $`;
169 0           my $lastDir = $1;
170 0           my $currentFileName = $_;
171 0 0         if ( not fileFilterQ($currentFile) ) {
172             # fileFilterQ It returns true in case of file, false in case of dir, not a text file.
173 0           return 1;
174             }
175             # open file. Read in the whole file.
176 0 0         if( not( open FILE, "<$currentFile" ) ) {
177 0           die("Error opening file: $!");
178             }
179 0           my $wholeFileString;
180 0           { local $/ = undef; $wholeFileString = ; };
  0            
  0            
181 0 0         if ( not( close(FILE) ) ) { die("Error closing file: $!"); }
  0            
182            
183             # do the replacement.
184 0           my $replaceCount = 0;
185 0           foreach my $key1 ( keys %findReplaceH ) {
186 0 0         my $pattern = ( $useRegexQ ? $key1 : quotemeta($key1) );
187 0           $replaceCount = $replaceCount + ( $wholeFileString =~ s/$pattern/$findReplaceH{$key1}/g );
188             }
189 0 0         if ( $replaceCount > 0 ) { # replacement has happened
190 0           push( @$refchangedFiles, $currentFile );
191 0           $totalFileChangedCount++;
192            
193             # do backup make a directory in the backup path, make a backup copy.
194 0           my $pathAdd = $currentDir;
195 0           $pathAdd =~ s[$folderPath][];
196 0           mkpath( "$backupRoot/$pathAdd", 0, 0777 );
197 0 0         copy( $currentFile, "$backupRoot/$pathAdd/$currentFileName" ) or die "error: file copying file failed on $currentFile\n$!";
198            
199             # write to the original and get the file mode.
200 0           my ( $mode, $uid, $gid ) = ( stat($currentFile) )[ 2, 4, 5 ];
201            
202             # write out a new file.
203 0 0         if ( not( open OUTFILE, ">$currentFile" ) ) { die("Error opening file: $!"); }
  0            
204 0           print OUTFILE $wholeFileString;
205 0 0         if ( not( close(OUTFILE) ) ) { die("Error closing file: $!"); }
  0            
206            
207             # set the file mode.
208 0           chmod( $mode, $currentFile );
209 0           chown( $uid, $gid, $currentFile );
210            
211 0 0         open( FILE, ">>$logFile" ) || die "cann't open the $!\n";
212 0           print FILE "---------------------------------------------\n";
213 0           print FILE "$replaceCount replacements made at\n";
214 0           print FILE "$currentFile\n";
215 0           close FILE;
216             }
217             }
218 0           find( \&processFile, $folderPath );
219 0 0         open( FILE, ">>$logFile" ) || die "cann't open the $!\n";
220 0           print FILE "--------------------------------------------\n";
221 0           print FILE "Total changed files -> $totalFileChangedCount\n";
222            
223 0 0         if ( scalar @$refchangedFiles > 0 ) {
224 0           print FILE "\nFollowing files are changed:\n";
225 0           print FILE Dumper($refchangedFiles);
226             }
227 0           close FILE;
228             }
229             sub Usage {
230 0     0 0   print<<'EOF';
231             Usage:
232             #!/usr/bin/perl
233             use File::Find::ProjectCycleMigration;
234             my $config = {year=>2011, srcdir=>'/home/uid/foo/project2011'};
235             FindReplace($config);
236            
237             File::Find::ProjectCycleMigration is to convert a project from one cycle to next. The Script scans
238             the code in provided path and auto generates a list of possible replacements
239             required for moving the code to the next cycle.
240             Once you run the script from command line it shows you the list of possible
241             replacements in your specified folder and prompts you to confirm or selectively
242             remove some of the auto generated list of replacements. enter a name of a
243             replacement key to remove it from the list of replacements or type yes or no to
244             continue or abort.
245            
246             --year= replace with 4-digits of current cycle year.
247             For example if you are moving the code base from 2011 to 2012 cycle
248             replace with 2011.
249             Required
250             --srcdir= replace with the absolute path of the directory where the replacement
251             should be made. Also script automatically backs up the current code in 'Back-up Directory'
252             and for logs it creates a 'Log Directory' at one level above the 'Current Directory'.
253             Required
254             EOF
255             }
256             sub separator{
257 0     0 0   my ($length, $symbol) = @_;
258 0           print "\t";foreach(1..$length){print $symbol}; print "\n";
  0            
  0            
  0            
259             }
260             sub textFormat{
261 0     0 0   my ($limit, $text) = @_;
262 0           my $ln = length($text);
263 0           my $sp=0;
264 0           while($ln>0){print "\t", (substr($text,$sp, $limit)) . "\n"; $sp += $limit;$ln -=$limit;}
  0            
  0            
  0            
265             }
266            
267             1;
268            
269             __END__