#!/usr/bin/perl # Copyright (C) 2005 Eric L. Wilhelm use warnings; use strict; use IPC::Run qw(run); use File::Basename; use File::Path qw(rmtree); our $svn = 'svn'; our $svk = 'svk'; our $sv = $svn; # XXX ick ($0 eq __FILE__) and exit main(@ARGV); sub main { my @dirs = @_; # XXX this is bad? (it means if we get require()'d that we can't dispatch) # XXX also, should I relink to myself to create all of my aliases? my $mode = basename($0); @dirs or die "usage: $mode ...\n"; ($mode =~ s/^svn_//) or die; my $func = dispatch($mode) or die "$mode is not one of ..."; run_loop(\@dirs, pattern => pattern($mode), method => $func); 0; } # end subroutine main definition ######################################################################## sub run_loop { my ($dirs, %opts) = @_; my $func = $opts{method} or die; my $pat = $opts{pattern}; ##print "pattern: $pat (", ref($pat), "\n"; my @dirs = @$dirs; foreach my $dir (@dirs) { my ($in, $out, $err); # XXX is this necessary/justified? (-e $dir) or die "no such directory: $dir"; $sv = $svn; { # XXX subcommands should check/assert as needed # only thing that requires dir to be a dir? my $lookdir = ((-d $dir) ? $dir : dirname($dir)) . '/.svn'; (-d $lookdir) or ($sv = $svk); } run([$sv, 'status', $dir], \$in, \$out, \$err) or die "ack ($dir) $? -> $err"; $out or next; my @new = map({s/$pat\s*//;$_} grep(/$pat/, split(/\n/, $out))); @new or next; ## warn join("\n ", "new for $dir: ", @new), "\n"; $func->(@new); } } # end subroutine run_loop definition ######################################################################## sub dispatch { my ($mode) = @_; # list of functions which accept a list of files as their argument my %table = ( adder => \&adder, cleaner => \&cleaner, diffs => \&diffs, remover => \&remover, ignorer => \&ignorer, ); return($table{$mode}); # XXX do we even need this? } # end subroutine dispatch definition ######################################################################## sub pattern { my ($mode) = @_; my %table = ( diffs => qr/^M.?/, remover => qr/^!/, ); return(exists($table{$mode}) ? $table{$mode} : qr/^\?/); } # end subroutine pattern definition ######################################################################## sub adder { my @new = @_; system($sv, 'add', @new) and die "ack: $! ($?)"; } # end subroutine adder definition ######################################################################## sub remover { my @gone = @_; system($sv, 'rm', @gone) and die "ack: $! ($?)"; } # end subroutine remover definition ######################################################################## sub cleaner { my @new = @_; foreach my $item (@new) { rmtree($item); # works on files or directories } } # end subroutine cleaner definition ######################################################################## sub diffs { my @changed = @_; # go through them backwards so they layer correctly foreach my $item (reverse(@changed)) { warn "$item\n"; run([$sv, 'diff', $item], '|', [ qw(gvim - -R), '--servername', "diff: $item", '--cmd', ':cd /tmp', '-c', ':set titlestring=', '-c', ':set syntax=diff', '-c', ':set nofoldenable', '-c', ':map q :q!' ], '>', '/dev/null' ); } } # end subroutine diffs definition ######################################################################## sub ignorer { my @created = @_; # XXX this is broken -- doesn't account for the ?'d file being in a # subdir system($sv, 'propset', 'svn:ignore', join("\n", @created), '.' ) and die "ack $! ($?)"; } # end subroutine ignorer definition ######################################################################## # vim:ts=2:sw=2:et:sta 1;