blob: 11b166690a5ce637ccbc765a1fed3f224d381502 [file] [log] [blame]
#! /usr/bin/perl
#
# testsvncopy.pl -- test script for svncopy.pl.
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
# NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston MA 02111-1307 USA.
#
# This product makes use of software developed by
# CollabNet (http://www.Collab.Net/), see http://subversion.tigris.org/.
#
# This software consists of voluntary contributions made by many
# individuals. For exact contribution history, see the revision
# history and logs, available at http://subversion.tigris.org/.
#------------------------------------------------------------------------------
#------------------------------------------------------------------------------
#
# This script tests the operation of svncopy.pl.
#
# For more information see the pod documentation at the foot of the file,
# or run testsvncopy.pl -?.
#
#------------------------------------------------------------------------------
#
# Include files
#
use Cwd;
use File::Temp 0.12 qw(tempdir tempfile);
use Getopt::Long 2.25;
use Pod::Usage;
use URI 1.17;
#
# Global definitions
#
# Specify the location of the svn command.
my $svn = '@SVN_BINDIR@/svn';
# The scratch repository location for the tests
my $testroot = '@SVN_TEST_REPOSITORY@';
# Input parameters
my $verbose = 0;
my @svn_options = ();
# Internal information
my %externals_hash;
my $temp_dir;
# Error handling
my @errors = ();
my @warnings = ();
# Testing-specific variables
my $hideerrors = 0;
#------------------------------------------------------------------------------
# Main execution block
#
#
# Process arguments
#
GetOptions( "verbose!" => sub { $verbose = 1; push( @svn_options, "--verbose" ) },
"quiet|q" => sub { $verbose = 0; push( @svn_options, "--quiet" ) },
"username=s" => sub { push( @svn_options, "--username", $_[1] ) },
"password=s" => sub { push( @svn_options, "--password", $_[1] ) },
"no_auth_cache" => sub { push( @svn_options, "--no-auth-cache" ) },
"force-log" => sub { push( @svn_options, "--force-log" ) },
"encoding=s" => sub { push( @svn_options, "--encoding", $_[1] ) },
"config-dir=s" => sub { push( @svn_options, "--config-dir", $_[1] ) },
"test-repository|t=s" => \$testroot,
"help|?" => sub{ Usage() },
) or Usage();
# Put in a signal handler to clean up any temporary directories.
sub catch_signal {
my $signal = shift;
warn "$0: caught signal $signal. Quitting now.\n";
exit 1;
}
$SIG{HUP} = \&catch_signal;
$SIG{INT} = \&catch_signal;
$SIG{TERM} = \&catch_signal;
$SIG{PIPE} = \&catch_signal;
# Make sure we're in the correct directory, saving current before we move
my $startDir = cwd;
if ( $0 =~ m"(.*[\\/])[^\\/]+$" )
{
my $programDir = $1;
chdir( $programDir );
}
# Run the tests
testUpdateExternals();
# Check whether they passed
if ( 0 != scalar( @errors ) )
{
print "\n*****************************************************************\n";
print "Errors:\n";
print @errors;
}
else
{
print "*** Script passed tests ***\n";
}
# Return to the original directory
chdir( $startDir );
exit( scalar( @errors ) );
#------------------------------------------------------------------------------
# Function: testUpdateExternals
#
# Tests the script, pushing any errors onto @errors.
#
# Parameters:
# none
#
# Returns: none
#------------------------------------------------------------------------------
sub testUpdateExternals
{
my $failed = 0;
my $retval;
my $testsubdir = "svncopy-update";
my $testURL = "$testroot/$testsubdir";
my @testdirs = (
"source/dirA/dir1",
"source/dirA/dir2",
"source/dirB/dir3",
"wibble/dirA/dir2",
);
my $dirWithExternals = $testdirs[0];
my $pinnedDir = $testdirs[1];
my $dest = "$testURL/dest";
my $old_verbose = $verbose;
my %revisions = {};
my $testRev;
my $test_externals =
"DIR2 $testURL/source/dirA/dir2\n". # 1 space
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2\n".
"DIR3 $testURL/source/dirB/dir3\n". # 5 spaces
"DIR4 $testURL/wibble/dirA/dir2"; # 2 tabs
my @tests = (
# Updating with nothing to update
{ sources => [ "$testURL/source/dirA/dir1", ],
pin => 0,
update => 1,
ext_dir => "dir1",
expected_externals => [
"DIR2 $testURL/source/dirA/dir2",
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
"DIR3 $testURL/source/dirB/dir3",
"DIR4 $testURL/wibble/dirA/dir2"
],
expected_tree => [
"dir1/",
],
},
# Updating a tree - enclosed should change, unless pinned
{ sources => [ "$testURL/source/dirA", ],
pin => 0,
update => 1,
ext_dir => "dirA/dir1",
expected_externals => [
"DIR2 $testURL/dest/dirA/dir2",
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
"DIR3 $testURL/source/dirB/dir3",
"DIR4 $testURL/wibble/dirA/dir2"
],
expected_tree => [
"dirA/",
"dirA/dir1/",
"dirA/dir2/",
],
},
# Updating with no update - no change
{ sources => [ "$testURL/source/dirA", ],
pin => 0,
update => 0,
ext_dir => "dirA/dir1",
expected_externals => [
"DIR2 $testURL/source/dirA/dir2",
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
"DIR3 $testURL/source/dirB/dir3",
"DIR4 $testURL/wibble/dirA/dir2"
],
expected_tree => [
"dirA/",
"dirA/dir1/",
"dirA/dir2/",
],
},
# Updating with two sources
{ sources => [ "$testURL/source/dirA/dir1",
"$testURL/source/dirB/dir3" ],
pin => 0,
update => 1,
ext_dir => "dir1",
expected_externals => [
"DIR2 $testURL/source/dirA/dir2",
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
"DIR3 $testURL/dest/dir3",
"DIR4 $testURL/wibble/dirA/dir2"
],
expected_tree => [
"dir1/",
"dir3/",
],
},
# Pinning
{ sources => [ "$testURL/source/dirA/dir1", ],
pin => 1,
update => 0,
ext_dir => "dir1",
expected_externals => [
"DIR2 -r __REV__ $testURL/source/dirA/dir2",
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
"DIR3 -r __REV__ $testURL/source/dirB/dir3",
"DIR4 -r __REV__ $testURL/wibble/dirA/dir2",
],
expected_tree => [
"dir1/",
],
},
# Pinning a tree
{ sources => [ "$testURL/source/dirA", ],
pin => 1,
update => 0,
ext_dir => "dirA/dir1",
expected_externals => [
"DIR2 -r __REV__ $testURL/source/dirA/dir2",
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
"DIR3 -r __REV__ $testURL/source/dirB/dir3",
"DIR4 -r __REV__ $testURL/wibble/dirA/dir2",
],
expected_tree => [
"dirA/",
"dirA/dir1/",
"dirA/dir2/",
],
},
# Pinning with two sources
{ sources => [ "$testURL/source/dirA/dir1",
"$testURL/source/dirB/dir3" ],
pin => 1,
update => 0,
ext_dir => "dir1",
expected_externals => [
"DIR2 -r __REV__ $testURL/source/dirA/dir2",
"DIR2Pin -r __PINREV__ $testURL/source/dirA/dir2",
"DIR3 -r __REV__ $testURL/source/dirB/dir3",
"DIR4 -r __REV__ $testURL/wibble/dirA/dir2",
],
expected_tree => [
"dir1/",
"dir3/",
],
},
);
my $auto_temp_dir = Temp::Delete->new();
my $test_temp_dir = $auto_temp_dir->temp_dir();
$temp_dir = $test_temp_dir;
print "\n################################################################\n";
print( "Testing svncopy.pl\n" );
info( "Using temporary directory $test_temp_dir\n" );
print( "Preparing source directory structure...\n" );
#
# Set up the source directory to copy
#
# Kill the directory if it's there
info( " - Deleting '$testURL'\n" );
SVNCall( 'delete', '-m', '"Preparing to test svncopy --update-externals"', $testURL );
# Now create the source directories
foreach my $dir ( @testdirs )
{
if ( !CreateTestDirectory( "$testURL/$dir" ) )
{
$failed = 1;
return;
}
}
# Check out the test root
if ( 0 != SVNCall( "co", $testURL, "$test_temp_dir/$testsubdir" ) )
{
error( "Preparatory checkout failed" );
$failed = 1;
return;
}
# Set an svn:externals on it
# - work our what externals we need to set (get the revision for the
# pinned directory)
my $pinnedRev = CurrentRevision( "$testURL/$pinnedDir" );
$test_externals =~ s|__PINREV__|$pinnedRev|gi;
# Now write the externals to a temporary file and set them on the dir.
my ($handle, $tmpfile) = tempfile( DIR => $test_temp_dir );
print $handle $test_externals;
close($handle);
if ( 0 != SVNCall( "propset", "svn:externals",
"--file", $tmpfile,
"$test_temp_dir/$testsubdir/$dirWithExternals" ) )
{
error( "svn propset of svn:externals failed" );
$failed = 1;
return;
}
# And commit them
if ( 0 != SVNCall( "commit", "-m",
"\"Testing svncopy --update_externals - adding svn:externals\"",
"$test_temp_dir/$testsubdir/$dirWithExternals" ) )
{
error( "svn commit failed" );
$failed = 1;
return;
}
#
# Also set a property on the pinned directory to make sure the pinned
# revision isn't the last one.
#
if ( 0 != SVNCall( "propset",
"svncopyTest",
"wibble",
"$test_temp_dir/$testsubdir/$pinnedDir" ) )
{
error( "svn propset of svncopyTest failed" );
$failed = 1;
return;
}
# And commit
if ( 0 != SVNCall( "commit", "-m",
"\"Testing svncopy --update_externals - adding svncopyTest property\"",
"$test_temp_dir/$testsubdir/$pinnedDir" ) )
{
error( "svn commit failed" );
$failed = 1;
return;
}
# Having done all the set-up, get our revision numbers.
foreach my $dir ( @testdirs )
{
$revisions{ "$testURL/$dir" } = CurrentRevision( "$testURL/$dir" );
}
print( "...Source directory structure complete\n" );
# Script parameters
my $message = "\"Testing svncopy.pl\"";
TEST: foreach my $testtype ( "HEAD", "-r" )
{
my @copy_options = @svn_options;
my $testno = 1;
# Do extra setup for -r
if ( "-r" eq $testtype )
{
$testRev = $revisions{ "$testURL/$pinnedDir" };
print "Updating repository to run --revision tests against revision ".
"$testRev...\n";
#
# Copy the same revision we did before
# The last thing we changed was the pinned directory, so
# take its revision as the one we want to copy.
#
push( @copy_options, "--revision", "$testRev" );
#
# Now add a file to each directory.
#
foreach my $dir ( @testdirs )
{
if ( !UpdateTestDirectory( "$test_temp_dir/$testsubdir/$dir" ) )
{
$failed = 1;
return;
}
}
# And commit
if ( 0 != SVNCall( "commit", "-m",
"\"Testing svncopy --update_externals".
" - updating directories for '--revision' test\"",
"$test_temp_dir/$testsubdir" ) )
{
error( "svn commit of updated directories failed" );
$failed = 1;
return;
}
print "...update done. Now re-running tests against new repository\n";
}
foreach my $test ( @tests )
{
my @cmd_options = @copy_options;
print "\n################################################################\n";
print "### test number $testno\n";
# Kill the destination directory if it's there
$verbose = 0;
SVNCall( 'delete', '-m', '"Preparing to test svncopy --update-externals"', $dest );
$verbose = $old_verbose;
my @sources = @{$test->{sources}};
my @expected_externals = @{$test->{expected_externals}};
my @expected_tree = @{$test->{expected_tree}};
# Update global parameters
push( @cmd_options, "--message", "$message" );
push( @cmd_options, "--tag" ) if ( $test->{pin} );
push( @cmd_options, "--branch" ) if ( $test->{update} );
# Now do the copy
my @cmdline = ( "perl", "svncopy.pl", @cmd_options, @sources, $dest );
info( "\n=> Calling ", join( " ", @cmdline ), "\n\n" );
if ( system( @cmdline ) )
{
error( "Copy failed" );
$failed = 1;
}
# Check that the generated tree is as expected.
if ( !CheckTree( $dest, @expected_tree ) )
{
# CheckTree outputs an error message if it fails
$failed = 1;
}
# And check the externals
my $ext_dir = "$dest/$test->{ext_dir}";
if ( !CheckExternals( $ext_dir, \%revisions, $pinnedRev, @expected_externals ) )
{
# CheckExternals outputs an error message if it fails
$failed = 1;
}
# Bomb out if we had an error
if ( $failed )
{
print "\n*** '$testtype' test $testno failed ***\n";
print "****************************************************************\n";
last TEST;
}
print "\n### '$testtype' test $testno passed\n";
print "################################################################\n";
$testno++;
}
}
if ( $failed ) { error( "*** svncopy tests failed\n" ); }
else { print "... svncopy tests passed\n"; }
}
#------------------------------------------------------------------------------
# Function: CreateTestDirectory
#
# Creates a directory in svn.
#
# Parameters:
# svnpath directory to create
#
# Returns: non-zero on success
#------------------------------------------------------------------------------
sub CreateTestDirectory
{
my $svnpath = $_[0];
my $test_uri = URI->new( "$svnpath" );
info( "Creating '$test_uri'\n" );
if ( !CreateSVNDirectories( $test_uri, "Testing svncopy --update_externals" ) )
{
error( "CreateSVNDirectories on '$test_uri' failed" );
return 0;
}
return 1;
}
#------------------------------------------------------------------------------
# Function: UpdateTestDirectory
#
# Modifies the directory in the working copy so that we can check the version
# copied is correct.
#
# Parameters:
# dir directory to modify (on file system)
#
# Returns: non-zero on success
#------------------------------------------------------------------------------
sub UpdateTestDirectory
{
my $dir = $_[0];
my $testfile = "$dir/test.txt";
# Create a file in the directory
if ( !open FILE, ">$testfile" )
{
error( "Couldn't create test file '$testfile'" );
return 0;
}
print FILE "Test file in '$dir'\n";
close FILE;
# Now add it to Subversion
if ( 0 != SVNCall( "add", $testfile ) )
{
error( "svn add '$testfile' failed" );
return 0;
}
# We're done
return 1;
}
#------------------------------------------------------------------------------
# Function: CheckTree
#
# Checks that directory structure in the subversion location matches
# the given tree.
#
# Parameters:
# svnpath Subversion location to check.
# expected Expected response - list of files and dirs as returned
# by svn list.
#
# Returns: non-zero on success
#------------------------------------------------------------------------------
sub CheckTree
{
my ( $svnpath, @expected ) = @_;
my ( $retval, @output ) = SVNCall( "list", "--recursive", $svnpath );
if ( 0 != $retval )
{
error( "svn list on '$svnpath' failed" );
return 0;
}
# Remove any blank lines and carriage returns
@output = grep( { chomp($_); $_ !~ m"^\s*$"} @output );
# Now compare with expected
my $compare_ctx = { list1 => [@expected], list2 => [@output] };
if ( 0 != CompareLists( $compare_ctx ) )
{
my $addedtext;
my $removedtext;
if ( @{$compare_ctx->{added}} )
{
$addedtext = "\n +".join( "\n +", @{$compare_ctx->{added}} );
}
if ( @{$compare_ctx->{removed}} )
{
$removedtext = "\n -".join( "\n -", @{$compare_ctx->{removed}} );
}
error( "'$svnpath' doesn't match expected$addedtext$removedtext\n" );
return 0;
}
return 1;
}
#------------------------------------------------------------------------------
# Function: CheckExternals
#
# Checks that the subversion location matches the given tree.
#
# Parameters:
# svnpath Subversion location to check.
# revisions Hash containing the revisions for externals.
# pinnedRev Revision of pinned directory.
# expected Expected response - list of externals as returned
# by svn propget svn:externals.
#
# Returns: non-zero on success
#------------------------------------------------------------------------------
sub CheckExternals
{
my ( $svnpath, $revisions, $pinnedRev, @expected ) = @_;
my @new_externals;
( $retval, @new_externals ) = SVNCall( "propget", "svn:externals", $svnpath );
if ( 0 != $retval )
{
error( "svn propget on '$svnpath' failed" );
return 0;
}
# Update @expected with revisions
@expected = grep
{
$_ =~ s|__PINREV__|$pinnedRev|g;
if ( $_ =~ m"(.*)\s+-r __REV__\s+(.*)" )
{
my $path = $1;
my $svnpath = $2;
my $rev = $revisions->{$svnpath};
$_ =~ s|__REV__|$rev|g;
}
1;
} @expected;
# Remove any blank lines and carriage returns from the output
@new_externals = grep( { chomp($_); $_ !~ m"^\s*$"} @new_externals );
# Now compare with expected
my $compare_ctx = { list1 => [@expected], list2 => [@new_externals] };
if ( 0 != CompareLists( $compare_ctx ) )
{
error( "Externals on '$svnpath' don't match expected\n".
" - expected:\n ".
join( "\n ", @expected ) .
"\n - actual:\n ".
join( "\n ", @new_externals )
);
return 0;
}
return 1;
}
#------------------------------------------------------------------------------
# Function: CurrentRevision
#
# Returns the repository revision of the last change to the given object.
#
# Parameters:
# source The URL to check
#
# Returns: The relevant revision number
#------------------------------------------------------------------------------
sub CurrentRevision
{
my $source = shift;
my $old_verbose = $verbose;
$verbose = 0;
my ( $retval, @output ) = SVNCall( "log -q", $source );
$verbose = $old_verbose;
if ( 0 != $retval )
{
error( "CurrentRevision: log -q on '$source' failed" );
return -1;
}
#
# The second line should give us the info we need: e.g.
#
# >svn log -q http://subversion/svn/scratch/ianb/svncopy-update/source/dirA
# ------------------------------------------------------------------------
# r1429 | ib | 2004-06-14 17:39:36 +0100 (Mon, 14 Jun 2004)
# ------------------------------------------------------------------------
# r1423 | ib | 2004-06-14 17:39:26 +0100 (Mon, 14 Jun 2004)
# ------------------------------------------------------------------------
# r1422 | ib | 2004-06-14 17:39:23 +0100 (Mon, 14 Jun 2004)
# ------------------------------------------------------------------------
# r1421 | ib | 2004-06-14 17:39:22 +0100 (Mon, 14 Jun 2004)
# ------------------------------------------------------------------------
#
# The second line starts with the latest revision number.
#
if ( $output[1] =~ m"^r(\d+) \|" )
{
return $1;
}
error( "CurrentRevision: log output not formatted as expected\n" );
return -1;
}
#------------------------------------------------------------------------------
# Function: SVNCall
#
# Makes a call to subversion.
#
# Parameters:
# command Subversion command
# options Other options to pass to Subversion
#
# Returns: exit status, output from command
#------------------------------------------------------------------------------
sub SVNCall
{
my ( $command, @options ) = @_;
my @commandline = ( $svn, $command, @options );
info( " > ", join( " ", @commandline ), "\n" );
my @output = qx( @commandline 2>&1 );
my $result = $?;
my $exit = $result >> 8;
my $signal = $result & 127;
my $cd = $result & 128 ? "with core dump" : "";
if ($signal or $cd)
{
error( "$0: 'svn $command' failed $cd: exit=$exit signal=$signal\n" );
}
if ( $exit > 0 )
{
info( join( "\n", @output ) );
}
if ( wantarray )
{
return ( $exit, @output );
}
return $exit;
}
#------------------------------------------------------------------------------
# Function: CreateSVNDirectories
#
# Creates a directory in Subversion, including all intermediate directories.
#
# Parameters:
# URI directory path to create.
# message commit message (optional).
#
# Returns: 1 on success, 0 on error
#------------------------------------------------------------------------------
sub CreateSVNDirectories
{
my ( $URI, $message ) = @_;
my $r = $URI->clone;
my @path_segments = grep { length($_) } $r->path_segments;
my @r_path_segments;
unshift(@path_segments, '');
$r->path('');
my $found_root = 0;
my $found_tail = 0;
# Prepare a file containing the message
my ($handle, $messagefile) = tempfile( DIR => $temp_dir );
print $handle $message;
close($handle);
my @msgcmd = ( "--file", $messagefile );
# We're going to get errors while we do this. Don't show the user.
my $old_verbose = $verbose;
$verbose = 0;
# Find the repository root
while (@path_segments)
{
my $segment = shift @path_segments;
push( @r_path_segments, $segment );
$r->path_segments( @r_path_segments );
if ( !$found_root )
{
if ( SVNCall( 'log', '-r', 'HEAD', $r ) == 0 )
{
# We've found the root of the repository.
$found_root = 1;
}
}
elsif ( !$found_tail )
{
if ( SVNCall( 'log', '-r', 'HEAD', $r ) != 0 )
{
# We've found the first directory which doesn't exist.
$found_tail = 1;
}
}
if ( $found_tail )
{
# We're creating directories
$verbose = $old_verbose;
if ( 0 != SVNCall( 'mkdir', @msgcmd, $r ) )
{
error( "Couldn't create directory '$r'" );
return 0;
}
}
}
$verbose = $old_verbose;
return 1;
}
#------------------------------------------------------------------------------
# Function: CompareLists
#
# Compares two lists.
#
# Parameters:
# context Structure containing the current state of the comparison:
# list1 [in] first list
# list2 [in] second list
# diffs [out] The number of differences
# added [out] The entries in list2 not in list1
# removed [out] The entries in list1 not in list2
# common [out] The entries in both lists
#
# Returns: The number of differences
#------------------------------------------------------------------------------
sub CompareLists
{
my $context = $_[0];
my %count = ();
# Make sure everything's clean
@{$context->{added}} = ();
@{$context->{removed}} = ();
@{$context->{common}} = ();
# Add the elements from list 1 into the hash
foreach $element( @{$context->{list1}} )
{
$count{$element}++;
}
# Add the elements from list 2 into the hash (negative)
foreach $element( @{$context->{list2}} )
{
$count{$element}--;
}
# Now elements in list1 only have a count of 1, in list2 only have a
# count of -1, and in both have a count of 0
foreach $element ( keys %count )
{
if ( 1 == $count{$element} ) { push( @{$context->{removed}}, $element ); }
elsif ( 0 == $count{$element} ) { push( @{$context->{common}}, $element ); }
else { push( @{$context->{added}}, $element ); }
}
$context->{diffs} = scalar( @{$context->{added}} ) +
scalar( @{$context->{removed}} );
return $context->{diffs};
}
#------------------------------------------------------------------------------
# Function: info
#
# Prints out an informational message in verbose mode
#
# Parameters:
# @_ The message(s) to print
#
# Returns: none
#------------------------------------------------------------------------------
sub info
{
if ( $verbose )
{
print @_;
}
}
#------------------------------------------------------------------------------
# Function: error
#
# Prints out and logs an error message
#
# Parameters:
# @_ The error messages
#
# Returns: none
#------------------------------------------------------------------------------
sub error
{
my $error;
# This is used during testing
if ( $hideerrors )
{
return;
}
# Now print out each error message and add it to the list.
foreach $error ( @_ )
{
my $text = "svncopy.pl: $error\n";
push( @errors, $text );
if ( $verbose )
{
print $text;
}
}
}
#------------------------------------------------------------------------------
# Function: Usage
#
# Prints out usage information.
#
# Parameters:
# optional error message
#
# Returns: none
#------------------------------------------------------------------------------
sub Usage
{
my $msg;
$msg = "\n*** $_[0] ***\n" if $_[0];
pod2usage( { -message => $msg,
-verbose => 0 } );
}
#------------------------------------------------------------------------------
# This package exists just to delete the temporary directory.
#------------------------------------------------------------------------------
package Temp::Delete;
use File::Temp 0.12 qw(tempdir);
sub new
{
my $this = shift;
my $class = ref($this) || $this;
my $self = {};
bless $self, $class;
my $temp_dir = tempdir("testsvncopy_XXXXXXXXXX", TMPDIR => 1);
$self->{tempdir} = $temp_dir;
return $self;
}
sub temp_dir
{
my $self = shift;
return $self->{tempdir};
}
sub DESTROY
{
my $self = shift;
my $temp_dir = $self->{tempdir};
if ( scalar( @errors ) )
{
print "Leaving $temp_dir for inspection\n";
}
else
{
info( "Cleaning up $temp_dir\n" );
File::Path::rmtree([$temp_dir], 0, 0);
}
# Return to the original directory
chdir( $startDir );
}
#------------------------------------------------------------------------------
# Documentation follows, in pod format.
#------------------------------------------------------------------------------
__END__
=head1 NAME
B<testsvncopy> - tests for B<svncopy> script
=head1 SYNOPSIS
B<testsvncopy.pl> [option ...]
B<testsvncopy.pl> tests the operation of the B<svncopy.pl> script.
Options:
-t [--test-repository] : URL to repository for root of tests
-q [--quiet] : print as little as possible
--username arg : specify a username ARG
--password arg : specify a password ARG
--no-auth-cache : do not cache authentication tokens
--force-log : force validity of log message source
--encoding arg : treat value as being in charset encoding ARG
--config-dir arg : read user configuration files from directory ARG
--[no]verbose : set the script to give lots of output
=head1 OPTIONS
=over 8
=item B<-t [--test-repository]>
Specify a URL to a scratch area of repository which the tests can use.
This can be any valid repository URL.
=item B<-q [--quiet]>
Print as little as possible
=item B<--username arg>
Specify a username ARG
=item B<--password arg>
Specify a password ARG
=item B<--no-auth-cache>
Do not cache authentication tokens
=item B<--force-log>
Force validity of log message source
=item B<--encoding arg>
Treat value as being in charset encoding ARG
=item B<--config-dir arg>
Read user configuration files from directory ARG
=item B<--[no]verbose>
Set the script to give lots of output when it runs
=item B<--help>
Print a brief help message and exits
=back
=head1 DESCRIPTION
B<svncopy.pl> is a utility script which performs an B<svn copy> command.
It allows extra processing to get around some limitations of the B<svn copy>
command (in particular related to branching and tagging).
B<testsvncopy.pl> tests the operation of this script.
=cut
#------------------------------- END OF FILE ----------------------------------