#!/usr/bin/perl -w use Term::ANSIColor qw(colored); use Getopt::Long; use strict; ######################## Customizable stuff ######################### ### This can be partially or completely overridden using -f, by ### ### putting stuff from here into a file and making modifications. ### ### Such files are read after executing this section, so lists ### ### must be appended to, etc. ### # The version control program being used (svn, git, bzr, cvs, etc). my $vc = 'svn'; # Files and directories that match any perl regexp in this list will # be ignored. This is independent of what $vc ignores. my @ignorables = (qr/^include/); # Text attribute to use for files or directories require user attention. my $ATT_ATT = "bold yellow"; # A table describing both commands and the output of $vc. my %translation = (); # $vc internal-speak -> $vc-speak $translation{'svn'} = {'add' => 'add', # Command to add to $vc. 'checkin' => 'ci', 'status' => 'status', # $vc's status command. 'uncontrolled' => qr/^\?/, # $vc's "unknown" char 'conflicted' => qr/^C/, 'locignore' => 'propset svn:ignore' }; # $0 will ignore any $novcdir directories, and mv stuff there if asked. # $novcdir is automatically added to @ignorables. my $novcdir = "${vc}-ignored"; ##################### End of customizable stuff ##################### sub usage { my ($msg, $exitval) = @_; if ($msg ne '') { print "$msg\n"; } print "\nUse: $0 [-h] [-f rcfile] [-c]\n"; print q { Report the version control status of the current directory's contents, and perform specified actions. Options: -c: Check-in if all goes well, exit with value 2 otherwise. -f : Read custom settings from somedir/rcfile. (See the "Customizable stuff" section of the code for details.) -h: Print this help message and exit. }; exit($exitval); } sub handle_uncontrolled { my $fn = $_[0]; my @add2ignore = (); my $req = ''; my $zero4ok = 1; print "Uncontrolled: "; print colored("$fn\n", $ATT_ATT); while (!$req) { print " (a)dd to $vc, add to ${vc}:(i)gnore, (m)v to $novcdir, (r)m, or (s)kip? "; #read STDIN, $req, 1; $req = ; chomp($req); } if ($req eq 'a') { system("$vc $translation{$vc}{'add'} $fn"); print " Added $fn to $vc\n"; $zero4ok = 0; } elsif ($req eq 'i') { #print colored(" Not implemented yet.\n", $ATT_ATT); push @add2ignore, $fn; } elsif ($req eq 'm') { my $dn = "./$fn"; my $bn = $fn; $dn =~ s,/[^/]*$,,; $dn .= "/$novcdir"; print "mving $fn to $dn.\n"; if (!-d $dn) { mkdir $dn or warn "Error $! making $dn"; } $bn =~ s,/$,,; $bn =~ s,^.*/,,; rename $fn, "$dn/$bn" or warn "Error $! mving $fn to $dn/$bn"; $zero4ok = 0; } elsif ($req eq 'r') { print "rming $fn."; system("rm -rf $fn"); $zero4ok = 0; } print "\n"; return $zero4ok, @add2ignore; } # Adds the paths in @_ to the properties to locally ignore in the future. sub add2locignores { my @locignores = @_; foreach my $locignpath (@locignores) { my $locdir = $locignpath; my $locfil = $locignpath; $locfil =~ s,.*/,,; $locdir =~ s,/$locfil$,,; my $cmdstr = "$vc $translation{$vc}{'locignore'} $locfil $locdir"; print "Executing $cmdstr\n"; system($cmdstr); } } ################################# main ################################### my $want_checkin = 0; my $rcfile = ""; my $help = 0; GetOptions('checkin|c' => \$want_checkin, 'rcfile|f=s' => \$rcfile, 'help|?|h' => \$help) or usage("", 1); usage("", 0) if ($help); if ($rcfile) { if (-f $rcfile) { open(RC, $rcfile) or die "Error $! opening $rcfile to read resources"; # Read whole file into 1 string. undef $/; my $customization = ; close(RC) or warn "Error $! closing $rcfile after reading resources."; $/ = "\n"; eval "$customization"; die "Error $@ applying customizations from $rcfile" if $@; print "novcdir = $novcdir\n"; } else { usage("Resource file $rcfile is not readable", 1); } } push @ignorables, $novcdir; my @locignores = (); my $zero4ok = 0; open(STATUS, "$vc $translation{$vc}{'status'} |") or die "Error $! reading the version control status with $vc $translation{$vc}{'status'}"; while () { /(\S+)\s+(.*)/; my ($status, $fn) = ($1, $2); my $ignore = 0; foreach my $ignorepat (@ignorables) { if ($fn =~ $ignorepat) { $ignore = 1; last; } } unless ($ignore) { if ($status =~ $translation{$vc}{'uncontrolled'}) { my ($success, @add2ignores) = handle_uncontrolled($fn); push @locignores, @add2ignores; $zero4ok += $success; } else { print "$status\t$fn\n"; } } } close(STATUS) or warn "Error $! closing $vc $translation{$vc}{'status'}"; # Now that the first $vc call is done, instate the requested additions to the # local ignore properties. add2locignores(@locignores); if ($want_checkin){ if (!$zero4ok) { open(CI, "$vc $translation{$vc}{'checkin'} |"); while () { print $_; } close(CI) or warn "Error $! closing $vc $translation{$vc}{'checkin'}"; } else { print "You skipped some things! Deal with them or checkin manually.\n"; } }