#!/usr/bin/perl -w # NAME: getdifflist.pl # AIM: Use the GNU diff utility to prepare a list for winmerge # 11/04/2013 - Some UI improvements # 16/03/2011 geoff mclane http://geoffair.net/mperl use strict; use warnings; use File::Basename; # split path ($name,$dir,$ext) = fileparse($file [, qr/\.[^.]*/] ) use Cwd; my $os = $^O; my $perl_dir = '/home/geoff/bin'; my $PATH_SEP = '/'; my $temp_dir = '/tmp'; if ($os =~ /win/i) { $perl_dir = 'C:\GTools\perl'; $temp_dir = $perl_dir; $PATH_SEP = "\\"; } unshift(@INC, $perl_dir); require 'lib_utils.pl' or die "Unable to load 'lib_utils.pl'! Check location and \@INC content.\n"; # log file stuff my ($LF); my $pgmname = $0; if ($pgmname =~ /(\\|\/)/) { my @tmpsp = split(/(\\|\/)/,$pgmname); $pgmname = $tmpsp[-1]; } my $outfile = $perl_dir."\\temp.$pgmname.txt"; open_log($outfile); # user variables my $VERS = "0.0.2 2013-04-11"; ##my $VERS = "0.0.1 2011-03-16"; my $load_log = 0; my $diff_opts = ''; my $def_diff_opts = "-urw"; my $ignore_repo = 1; # ignore files in a repo directory my $out_file = $perl_dir.$PATH_SEP."tempwm.bat"; my $user_output = 0; my $reverse_input = 1; my $wm_opts = "/u /e /w1"; my @week_days = qw(Mon Tue Wed Thu Fri Sat Sun); my $verbose = 0; my $out_diff = $perl_dir.$PATH_SEP."tempdiff.diff"; my $out_diff_all = $perl_dir.$PATH_SEP."tempall.diff"; my $out_diff_ign = $perl_dir.$PATH_SEP."tempignored.diff"; my $add_only_in = 1; # debug my $debug_on = 0; my $def_file1 = 'C:\FGCVS\Atlas'; my $def_file2 = 'C:\FG\Atlas\Atlas-0.5.0'; ### program variables my $in_file1 = ''; my $in_file2 = ''; my @warnings = (); my $cwd = cwd(); my $found_count = 0; my $ignored_count = 0; sub show_warnings($) { my ($val) = @_; if (@warnings) { prt( "\nGot ".scalar @warnings." WARNINGS...\n" ); foreach my $itm (@warnings) { prt("$itm\n"); } prt("\n"); } else { #prt( "\nNo warnings issued.\n\n" ); } } sub pgm_exit($$) { my ($val,$msg) = @_; if (length($msg)) { $msg .= "\n" if (!($msg =~ /\n$/)); prt($msg); } show_warnings($val); close_log($outfile,$load_log); exit($val); } sub prtw($) { my ($tx) = shift; $tx =~ s/\n$//; prt("$tx\n"); push(@warnings,$tx); } sub VERB1() { return ($verbose >= 1); } sub VERB2() { return ($verbose >= 2); } sub VERB5() { return ($verbose >= 5); } sub VERB9() { return ($verbose >= 9); } sub set_output_per_path() { return if ($user_output); return if (! exists $ENV{'PATH'} ); my $path = $ENV{'PATH'}; my @arr = split(';',$path); my ($dir); foreach $dir (@arr) { if ($dir =~ /^C:\\MDOS$/i) { my ($n,$d) = fileparse($out_file); $out_file = $dir.$PATH_SEP.$n; return; } } } sub check_diff($) { my ($verb) = shift; if (open (DIFF, "diff --version |")) { my @arr = ; close DIFF; my $ntx = ''; foreach my $ln (@arr) { chomp $ln; if( length($ln) ) { $ntx .= "\n" if length($ntx); $ntx .= $ln; } } prt("$ntx\n") if ($verb); return 1; } return 0; } sub has_repo_folder($) { my $f = shift; return 1 if ($f =~ /(\\|\/)CVS(\\|\/)/); return 2 if ($f =~ /(\\|\/)\.svn(\\|\/)/); return 3 if ($f =~ /(\\|\/)\.git(\\|\/)/); return 4 if ($f =~ /(\\|\/)\.hg(\\|\/)/); return 0; } sub get_diff_array($$) { my ($inf1,$inf2) = @_; my @arr = (); prt("Moment, processing 'diff $diff_opts $inf1 $inf2'..."); if (open (DIFF, "diff $diff_opts $inf1 $inf2 |")) { @arr = ; close DIFF; write2file(join("",@arr),$out_diff_all); prt(" written [$out_diff_all]\n"); } else { prt(" DIFF FAILED!\n"); } return \@arr; } sub get_day_off($) { my $line = shift; my ($day,$off); foreach $day (@week_days) { $off = index($line, $day); return $off if ($off > 0); } return -1; } sub process_inputs($$) { my ($inf1,$inf2) = @_; if ((-d $inf1)&&(-d $inf2)) { $diff_opts = $def_diff_opts if (length($diff_opts) == 0); } my $ra = get_diff_array($inf1,$inf2); my $cnt = scalar @{$ra}; prt("Got $cnt lines of diff...\n") if (VERB2()); my ($i,$line1,$line2,$i2,$off1,$off2,$nline); my @nlines = (); my @only_in = (); my @diff_lines = (); my @ignored_lines = (); my $ignore_set = 0; for ($i = 0; $i < $cnt; $i++) { $i2 = $i + 1; # get PAIR of lines from 'diff' $line1 = ${$ra}[$i]; $line2 = ($i2 < $cnt) ? ${$ra}[$i2] : "\n"; chomp $line1; chomp $line2; if (($line1 =~ /^---\s+/)&&($line2 =~ /^\+\+\+\s+/)) { if ($ignore_repo && (has_repo_folder($line1) || has_repo_folder($line2))) { $ignored_count++; } else { $line1 =~ s/^---\s+//; $line2 =~ s/^\+\+\+\s+//; $off1 = get_day_off($line1); $off2 = get_day_off($line2); $line1 = substr($line1,0,$off1) if ($off1 > 0); $line2 = substr($line2,0,$off2) if ($off2 > 0); $line1 = trim_tailing($line1); $line2 = trim_tailing($line2); if ($reverse_input) { $nline = "\@call wm $wm_opts $line2 $line1"; } else { $nline = "\@call wm $wm_opts $line1 $line2"; } prt("$nline\n") if (VERB1()); push(@nlines,$nline); $found_count++; } } elsif ($line1 =~ /^diff\s+/) { # first diff line if ($ignore_repo && has_repo_folder($line1)) { $ignore_set = 1; } else { $ignore_set = 0; } } elsif ($line1 =~ /^Only\s+in\s+/ ) { # Only in line if ($ignore_repo && has_repo_folder($line1)) { $ignore_set = 1; # ignored } else { push(@only_in,$line1); $ignore_set = 0; } } elsif ($line1 =~ /^Binary\s+files\s+/) { # Binary files if ($ignore_repo && has_repo_folder($line1)) { $ignore_set = 1; # ignored } else { $ignore_set = 0; } } elsif ($line1 =~ /^\@\@\s+(.+)\@\@\s*$/) { # start of diff block } $line1 = ${$ra}[$i]; # get line back if ($ignore_set) { push(@ignored_lines,$line1); } else { push(@diff_lines,$line1); } } if ($found_count) { prt("Found $found_count pairs."); prt(" Ignored $ignored_count files.") if ($ignored_count); prt("\n"); $nline = ''; $cnt = 0; foreach $line1 (@nlines) { $cnt++; $nline .= "$line1\n"; if ($cnt < $found_count) { $nline .= "\@echo Done $cnt of $found_count: Enter to process next...\n"; $nline .= "\@pause\n"; } else { $nline .= "\@echo Done $cnt of $found_count: End of list...\n"; } } $cnt = scalar @only_in; if ($add_only_in && $cnt) { $nline .= "\@echo Note the following list of $cnt 'Only in' entries\n"; foreach $line1 (sort @only_in) { $nline .= "\@echo $line1\n"; } } set_output_per_path(); write2file($nline,$out_file); prt("Batch file written to [$out_file]\n"); } else { prt("No file found in $cnt lines???\n"); } write2file(join("",@ignored_lines),$out_diff_ign); prt("Written ignored lines to [$out_diff_ign]\n"); write2file(join("",@diff_lines),$out_diff); prt("Written diff lines to [$out_diff]\n"); } ######################################### ### MAIN ### if (!check_diff(0)) { prt("A native WIN32 port of some GNU utilities can be found at\n". "http://unxutils.sourceforge.net/ Maybe download an install 'diff' in your PATH\n"); pgm_exit(1,"ERROR: Unable to run the 'diff' utility.\nCheck 'diff' is in your PATH!\n"); } parse_args(@ARGV); process_inputs($in_file1,$in_file2); pgm_exit(0,"Normal exit(0)"); ######################################## sub give_help { set_output_per_path(); prt("$pgmname: version $VERS\n"); prt("Usage: $pgmname [options] input1 input2\n"); prt("Options:\n"); prt(" --help (-h or -?) = This help, and exit 0.\n"); prt(" --all (-a) = Set all files. (def is to ignore repo folders CVS/.svn/.git)\n"); prt(" --diff (-d) = Set 'diff' options. (def=$def_diff_opts if none given).\n"); prt(" --out (-o) = Set batch output file. (def=$out_file).\n"); prt(" --verb[nn] (-v) = Bump or set verbosity. (def=$verbose)\n"); prt("Enter two directories, or files to compare using GNU 'diff',\n"); prt(" and create a WinMerge batch to view those different.\n"); prt("It is normal to put the oldest first, but this will be reversed for wm.\n"); #prt("diff version "); check_diff(1); } sub need_arg { my ($arg,@av) = @_; pgm_exit(1,"ERROR: [$arg] must have following argument!\n") if (!@av); } # need input of two folders or files sub parse_args { my (@av) = @_; my ($arg,$sarg,$icnt); $icnt = 0; while (@av) { $arg = $av[0]; if ($arg =~ /^-/) { $sarg = substr($arg,1); $sarg = substr($sarg,1) while ($sarg =~ /^-/); if (($sarg =~ /^h/i)||($sarg eq '?')) { give_help(); pgm_exit(0,"Help exit(0)"); } elsif ($sarg =~ /^a/) { $ignore_repo = 0; prt("Set ignore repo OFF\n"); } elsif ($sarg =~ /^d/) { need_arg(@av); shift @av; $sarg = $av[0]; $diff_opts = $sarg; prt("Set 'diff' options to [$diff_opts]\n"); } elsif ($sarg =~ /^o/) { need_arg(@av); shift @av; $sarg = $av[0]; $out_file = $sarg; $user_output = 1; prt("Set output file to [$out_file]\n"); } elsif ($sarg =~ /^v/) { if ($sarg =~ /^v(\d+)$/) { $verbose = $1; prt("Set verbosity to $verbose\n"); } else { while ($sarg =~ /^v/) { $verbose++; $sarg = substr($sarg,1); } } } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! Try -?\n"); } } else { if ($icnt == 0) { $in_file1 = $arg; prt("Set input 1 to [$in_file1]\n"); } elsif ($icnt == 1) { $in_file2 = $arg; prt("Set input 2 to [$in_file2]\n"); } else { pgm_exit(1,"ERROR: Invalid argument [$arg]! On two bare inputs expected.\n"); } $icnt++; } shift @av; } if ((length($in_file1) == 0) && $debug_on) { $in_file1 = $def_file1; } if ((length($in_file2) == 0) && $debug_on) { $in_file2 = $def_file2; } if (length($in_file1) == 0) { pgm_exit(1,"ERROR: No input files/directories found in command!\n"); } if (length($in_file2) == 0) { pgm_exit(1,"ERROR: No 2nd input file/directory found in command!\n"); } if (( ! -f $in_file1)&&( ! -d $in_file1)) { pgm_exit(1,"ERROR: Unable to find in file or dierctory [$in_file1]! Check name, location...\n"); } if (( ! -f $in_file2)&&( ! -d $in_file2)) { pgm_exit(1,"ERROR: Unable to find in file or dierctory [$in_file2]! Check name, location...\n"); } } # eof - getdifflist.pl