#!/usr/bin/perl -w use strict; use Getopt::Long qw(GetOptions); use Pod::Usage qw(pod2usage); use File::Basename qw(basename); my $VERSION = '0.01'; use Data::Dumper; my %opts; GetOptions(\%opts, "list", "save=s", "delete=s", "force", "keep", "restore=s", "help", "menu"); pod2usage(1) if $opts{help}; pod2usage(1) if not $opts{list} and not $opts{save} and not $opts{delete} and not $opts{restore} and not $opts{menu}; #print Dumper \%opts; #exit; my $patch = "/usr/bin/patch"; my $svn = "/usr/bin/svn"; my $subversion = "$ENV{HOME}/.subversion/switch"; my @list; read_list(); if (not -d $subversion) { mkdir $subversion or die "Cannot create switch directory '$subversion'\n"; } if ($opts{list}) { list_patches(); exit; } if ($opts{save}) { my $file = check_name($opts{save}); if (-e $file and not $opts{force}) { die "Change '$opts{save}' already exists. Use --force to overwrite\n" } system "$svn diff > $file"; if (not $opts{keep}) { system "$svn revert --recursive ."; } exit; } if ($opts{delete}) { my $file = check_name($opts{delete}); if (not -e $file) { die "This patch does not exists in $subversion\n"; } if ($opts{force}) { unlink $file or die $!; exit; } print "Do you really want to remove '$opts{delete}' [yN]?"; chomp(my $resp = ); if (grep {$resp eq $_} qw(y Y Yes)) { unlink $file or die $!; } else { print "OK, we keep $opts{delete}\n"; } exit; } if ($opts{restore}) { restore_patch($opts{restore}); } sub restore_patch { my ($param) = @_; if ($param =~ /^\d+$/) { die "Invalid number '$param'\n" if not defined $list[$param-1]; $param = $list[$param-1]; } my $file = check_name($param); if (not -e $file) { die "Could not find $param\n"; } my $diff = `$svn diff`; if ($diff and not $opts{force}) { die "There is a change in the workspace, use --force to remove it\n"; } if ($diff) { system "$svn revert --recursive ."; } system "$patch -p0 < $file"; exit; } if ($opts{menu}) { while (1) { my ($sel, $param) = menu_selection(); exit if $sel eq 'X'; list_patches() if $sel eq "L"; restore_patch($param) if $sel eq "R"; } } sub menu_selection { print "(L) List\n"; print "(D) Delete (D n)\n"; print "(S) Save (S n) or (S name for new)\n"; print "(R) Restore (R n)\n"; print "(X) Exit\n"; while (1) { chomp(my $selection = ); next if $selection eq ""; my ($sel, $param) = $selection =~ /^(.)\s*(.*?)\s*$/; print "$param\n"; if (grep {uc($sel) eq $_} qw(L X D S R)) { print "----------------------------\n"; return (uc $sel, $param); } else { print "Invalid selection. Try again.\n"; } } } sub read_list { my @patches = <$subversion/*.diff>; @list = map {$_ = basename $_; s/.diff$//; $_} @patches; } sub list_patches { #read_list(); my $i = 0; if (@list) { print map {$i++; "$i) $_\n"} @list; } else { print "We could not find any saved workspace in $subversion\n"; } print "\n"; } sub check_name { my ($name) = @_; return "$subversion/$name.diff" if $name =~ /^\w[\w-]*$/; die "Invalid change name. It must only use a-z characters\n"; } =head1 SYNOPSIS svnswitch --list svnswitch --delete NAME [--force] delete an existing patch from the switch directory if --force then won't even ask questions svnswitch --save NAME [--force] [--keep] save the current change as NAME and revert ws to original status --force will overwrite an existing saved patch with the same name --keep will keep the workspace as it is (no revert) svnswitch --restore NAME restore another change (patch the WS with NAME.diff) svnswitch --menu interactive operations =head1 OTHER IDEA When starting to work on a chane it is an anonymous change User can give a name to the current change If there is a name of the current change user can change to another name. The current change will be saved under the given name if the new name is an existing change it will be restored if not then a new empty change will be started (but one that already has a name) =head1 TODO Deal with Windows and other OSes (location of svn, patch is missing, etc.) Should we check if we are in the top-most directory of a repository ? Should we save the place in the tree where the diff was created so later we will not try to apply the diff in another location ? =head1 AUTHOR Gabor Szabo based on comments on the users mailing list from Norbert Unterberg David Faure =cut