Rev 7322 | Blame | Compare with Previous | Last modification | View Log | RSS feed
######################################################################### COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.## Module name : jats_svn.pl# Module type : Jats Utility# Compiler(s) : Perl# Environment(s): Jats## Description : A script to perform a number of SVN utility functions# The script will:# Delete a package# Create a package# Import source to a package###......................................................................#require 5.006_001;use strict;use warnings;use JatsError;use JatsSvn qw(:All);use JatsLocateFiles;use JatsProperties;use FileUtils;use Pod::Usage; # required for help supportuse Getopt::Long qw(:config require_order); # Stop on non-optionuse Cwd;use File::Path;use File::Copy;use File::Basename;use File::Compare;use Encode;my $VERSION = "1.0.0"; # Update this## Options#my $opt_debug = $ENV{'GBE_DEBUG'}; # Allow global debugmy $opt_verbose = $ENV{'GBE_VERBOSE'}; # Allow global verbosemy $opt_help = 0;## Globals#my $opr_done; # User has done something#-------------------------------------------------------------------------------# Function : Mainline Entry Point## Description :## Inputs :#my $result = GetOptions ("help:+" => \$opt_help, # flag, multiple use allowed"manual:3" => \$opt_help, # flag"verbose:+" => \$opt_verbose, # flag, multiple use allowed);## UPDATE THE DOCUMENTATION AT THE END OF THIS FILE !!!### Process help and manual options#pod2usage(-verbose => 0, -message => "Version: $VERSION") if ($opt_help == 1 || ! $result);pod2usage(-verbose => 1) if ($opt_help == 2 );pod2usage(-verbose => 2) if ($opt_help > 2);## Configure the error reporting process now that we have the user options#ErrorConfig( 'name' =>'SVN','verbose' => $opt_verbose,);## Reconfigure the options parser to allow subcommands to parse options#Getopt::Long::Configure('permute');InitFileUtils();## Process command# First command line argument is a subversion command#my $cmd = shift @ARGV || "help";CreatePackage() if ( $cmd =~ m/^create/ );CreateBranch() if ( $cmd =~ m/^branch/ );SwitchBranch() if ( $cmd =~ m/^switch/ );DeleteBranch() if ( $cmd =~ m/^delete-branch/ );DeletePackage() if ( $cmd =~ m/^delete-package/ );ImportPackage() if ( $cmd =~ m/^import/ );SvnRepoCmd($cmd, @ARGV) if ( $cmd eq 'ls' );TestSvn() if ($cmd eq 'test');ShowPaths() if ( $cmd =~ m/^path/ );ShowTag() if ( $cmd =~ m/^tag/ );ShowUrl() if ( $cmd =~ m/^url/ );SvnMerge() if ( $cmd =~ m/^merge/ );SvnReintegrate() if ( $cmd =~ m/^reintegrate/ );pod2usage(-verbose => 0, -message => "No valid operations specified") unless ( $opr_done );exit 0;#-------------------------------------------------------------------------------# Function : ShowPaths## Description : Show PATHS## Inputs :## Returns :#sub ShowPaths{## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Subversion Paths") if ($opt_help || $#ARGV >= 0);## Display known PATHS#my ( $pSVN_URLS, $pSVN_URLS_LIST) = SvnPaths();print ("Configured SubVersion Repository Paths\n");print sprintf(" %-20s %s\n", 'Tag', 'URL Prefix');foreach my $key ( @{$pSVN_URLS_LIST} ){print sprintf(" %-20s %s\n", $key || 'Default', $pSVN_URLS->{$key} );}$opr_done = 1;}#-------------------------------------------------------------------------------# Function : ShowTag## Description : Convert a URL into a TAG# Convert the current workspace info into a TAG## Inputs : url - Url to convert (optional)# Options# -help[=n] - Show help# -man - Show manual# -url=url - Convert URL# -path=path - Convert Workspace## Returns : Nothing#sub ShowTag{my $opt_path;my $opt_url;## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"path:s" => \$opt_path,"url:s" => \$opt_url,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Url to Tag") if ($opt_help);## Bare argument is a URL# If no arguments provided assume a path of the current directory#$opt_url = shift (@ARGV) if ( $#ARGV == 0 );$opt_path = '.' unless ( defined $opt_path || defined $opt_url );## Sanity Tests#Error ("Cannot specify both a URL and a PATH")if ( defined $opt_url && defined $opt_path );Warning ("Too many arguments") if ( $#ARGV >= 0 );# Do all the hard work#my $uref;if ( $opt_url ){$uref = NewSessionByUrl ( $opt_url );$uref->CalcRmReference($uref->Full());}else{$uref = NewSessionByWS($opt_path, 0, 1);my $ws_root = $uref->SvnLocateWsRoot(1);$uref->CalcRmReference($uref->FullWs());}Message ("Tag is : " . $uref->RmRef() );Message ("Vcs Tag : " . $uref->SvnTag );$opr_done = 1;}#-------------------------------------------------------------------------------# Function : ShowUrl## Description : Convert a TAG into a URL# Show the current workspace URL## Inputs : tag - Tag to convert (optional)# Options# -help[=n] - Show help# -man - Show manual# -tag=tag - Convert TAG# -path=path - Convert Workspace## Returns : Nothing#sub ShowUrl{my $opt_path;my $opt_tag;## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"path:s" => \$opt_path,"tag:s" => \$opt_tag,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Tag to Url") if ($opt_help);## Bare argument is a TAG# If no arguments provided assume a path of the current directory#$opt_tag = shift (@ARGV) if ( $#ARGV == 0 );$opt_path = '.' unless ( defined $opt_path || defined $opt_tag );## Sanity Tests#Error ("Cannot specify both a TAG and a PATH")if ( defined $opt_tag && defined $opt_path );Warning ("Too many arguments") if ( $#ARGV >= 0 );# Do all the hard work#my $uref;my $url;if ( $opt_tag ){my $path = $opt_tag;my $label;$path =~ s~^SVN::~~;if ( $path =~ m~(.+)::(.+)~ ){$path = $1;$label = $2;}$url = SvnPath2Url($path);if ( $label && $label =~ m~^\d+$~ ){$url .= '@' . $label;}elsif ( $label ){$url =~ m~(.+)(/(tags|branches|trunk)(/|$|@))~;$url = $1 . '/tags/'. $label;}}else{$uref = NewSessionByWS($opt_path, 0, 1);my $ws_root = $uref->SvnLocateWsRoot(1);$url = $uref->FullWsRev();}Message ("Url: $url");$opr_done = 1;}#-------------------------------------------------------------------------------# Function : TestSvn## Description : Test access to subversion## Inputs : None## Returns :#sub TestSvn{## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Test Subversion") if ($opt_help || $#ARGV >= 0);SvnUserCmd( '--version');$opr_done = 1;}#-------------------------------------------------------------------------------# Function : SvnRepoCmd## Description : Execute a SVN command, where the first argument# is a repository specifier## Inputs : $cmd# $repo_url# @opts## Returns :#sub SvnRepoCmd{my ( $cmd, $repo_url, @opts ) = @_;my $uref = NewSessionByUrl ( $repo_url );SvnUserCmd( $cmd,$uref->Full,@opts,{ 'credentials' => 1 });$opr_done = 1;}#-------------------------------------------------------------------------------# Function : DeletePackage## Description : Delete a Package structure within a Repository# Intended for test usage## Inputs : URL - Url to Repo + Package Base## Returns :#sub DeletePackage{my $opt_error = 0;## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"error!" => \$opt_error,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Delete a Package") if ($opt_help || $#ARGV < 0);## Sanity Tests#Message ("Delete Entire Package Tree" );Warning ("Too many arguments: @ARGV") if ( $#ARGV >= 1 );## Do all the hard work# Create# Import# Label#my $uref = NewSessionByUrl ( $ARGV[0] );$uref->SvnValidatePackageRoot(!$opt_error);$uref->SvnDelete ('target' => $uref->Full,'comment' => [$uref->Path().": Delete Package",'Deleted by user command: jats svn delete-package'],'noerror' => !$opt_error,);$opr_done = 1;}#-------------------------------------------------------------------------------# Function : CreatePackage## Description : Create a Package structure within a Repository# Optionally Import Data# Optionally Tag the import# Optionally Tag the import on a branch## Inputs : URL - Url to Repo + Package Base# Options - Command modifiers# -import=path - Import named directory# -label=name - Label the result# -tag=name - Import to Tag Only# -branch=name - Import to Branch only# -new - Must be new package# -replace - Replace existing## Returns :#sub CreatePackage{my $opt_import;my $opt_tag;my $opt_branch;my $opt_trunk;my $opt_new;my $opt_label;my $opt_replace;my $pname;my $type;my $opt_author;my $opt_date;Message ("Create New Package Version" );## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"verbose:+" => \$opt_verbose,"import=s" => \$opt_import,"new" => \$opt_new,"branch=s" => \$opt_branch,"trunk" => \$opt_trunk,"tags=s" => \$opt_tag,"label=s" => \$opt_label,"replace" => \$opt_replace,'author=s' => \$opt_author,'date=s' => \$opt_date,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Create a Package Version") if ($opt_help || $#ARGV < 0);## Alter the error reporting parameters#ErrorConfig( 'verbose' => $opt_verbose );## Sanity Tests#my $count = 0;$count++ if ( $opt_trunk );$count++ if ( $opt_branch );$count++ if ( $opt_tag );Error ("Conflicting options: -trunk, -tag, -branch") if ( $count > 1 );Error ("Nothing imported to be labeled") if ( $count && !$opt_import );Error ("Import path does not exist: $opt_import") if ( $opt_import && ! -d $opt_import );Error ("Conflicting options: new and replace") if ( $opt_new && $opt_replace );Error ("Too many command line arguments") if ( exists $ARGV[1] );$type = 'tags/' . $opt_tag if ( $opt_tag);$type = 'branches/' . $opt_branch if ( $opt_branch );$type = 'trunk' if ( $opt_trunk);## Do all the hard work# Create# Import# Label#my $uref = NewSessionByUrl ( $ARGV[0] );$uref->SvnCreatePackage ('import' => $opt_import,'label' => $opt_label,'type' => $type,'new' => $opt_new,'replace' => $opt_replace,);## Report RmPath as using a pegged version of a new package is a bit silly## Message ("Repository Ref: " . $uref->RmPath);# Message ("Vcs Tag : " . $uref->SvnTag);if ( $uref->{REVNO} ){$uref->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));$uref->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));}$opr_done = 1;}#-------------------------------------------------------------------------------# Function : ImportPackage## Description : Import a new version of a package# Take great care to reuse file-versions that are already in# the package## Intended to allow the importation of multiple# versions of a package## Inputs :## Returns :#sub ImportPackage{Message ("Import Package Version" );## Options#my $opt_package;my $opt_dir;my $opt_label;my $opt_replace = 0;my $opt_reuse;my $opt_workdir = "SvnImportDir";my $opt_delete = 1;my $opt_author;my $opt_date;my $opt_log = '';my $opt_branch;my $opt_datafile;my $opt_printfiles;my $opt_commit = 1;my $opt_mergePaths;## Other globals#my $url_label;my $url_branch;my $filesBase = 0; # Files in Base workspacemy $filesDeleted = 0; # Files Deletedmy $filesAdded = 0; # Files Addedmy $filesTransferred = 0; # Files Copiedmy $dirsDeleted = 0; # Directories Deletedmy $dirsAdded = 0; # Directories Addedmy $dirsTransferred = 0; # Directories Copied## Configuration options#my $result = GetOptions ('help:+' => \$opt_help,'manual:3' => \$opt_help,'verbose:+' => \$opt_verbose,'package=s' => \$opt_package,'dir=s' => \$opt_dir,'label=s' => \$opt_label,'branch=s' => \$opt_branch,'replace' => \$opt_replace,'reuse' => \$opt_reuse,'workspace=s' => \$opt_workdir,'delete!' => \$opt_delete,'printfiles=i' => \$opt_printfiles,'author=s' => \$opt_author,'date=s' => \$opt_date,'log=s' => \$opt_log,'datafile=s' => \$opt_datafile,'commit!' => \$opt_commit,'mergePaths=s' => \$opt_mergePaths,## Update documentation at the end of the file#) || Error ("Invalid command line" );## Insert defaults# User can specify base package via -package or a non-options argument#$opt_package = $ARGV[0] unless ( $opt_package );unlink $opt_datafile if ( defined $opt_datafile );## Subcommand specific help#SubCommandHelp( $opt_help, "Import directory to a Package")if ($opt_help || ! $opt_package );## Alter the error reporting parameters#ErrorConfig( 'verbose' => $opt_verbose );## Configure the error reporting process now that we have the user options#Error ("No package URL specified") unless ( $opt_package );Error ("No base directory specified") unless ( $opt_dir );Error ("Invalid base directory: $opt_dir") unless ( -d $opt_dir );Error ("Cannot label if not committing") if ( $opt_label && ! $opt_commit );## Create an SVN session#my $svn = NewSessionByUrl ( $opt_package );## Ensure that the required label is available#if ( $opt_label ){$opt_label = SvnIsaSimpleLabel ($opt_label);$url_label = $svn->BranchName( $opt_label, 'tags' );$svn->SvnValidateTarget ('target' => $url_label,'available' => 1,) unless ( $opt_replace );}## Validate the required branch# It will be created if it doesn't exist#if ( $opt_branch ){$opt_branch = SvnIsaSimpleLabel($opt_branch);$url_branch = $svn->BranchName( $opt_branch, 'branches' );my $rv = $svn->SvnValidateTarget ('cmd' => 'SvnImporter. Create branch','target' => $url_branch,'create' => 1,);if ( $rv == 2 ){$svn->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));$svn->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));}}## Create a workspace based on the users package# Allow the workspace to be reused to speed up multiple# operations#unless ( $opt_reuse && -d $opt_workdir ){Message ("Creating Workspace");rmtree( $opt_workdir );$svn->SvnValidatePackageRoot ();#DebugDumpData( 'Svn', $svn );$svn->SvnValidateTarget ('cmd' => 'SvnImporter','target' => $svn->Full,'require' => 1,);my $url_co = $opt_branch ? $url_branch : $svn->Full . '/trunk';$svn->SvnCo ( $url_co, $opt_workdir, 'print' => $opt_printfiles );Error ("Cannot locate the created Workspace")unless ( -d $opt_workdir );}else{Message ("Reusing Workspace");}## Determine differences between the two folders# Create structures for each directory#Message ("Determine Files in packages");my $search = JatsLocateFiles->new("--Recurse=1","--DirsToo","--FilterOutRe=/\.svn/","--FilterOutRe=/\.svn\$","--FilterOutRe=^/${opt_workdir}\$","--FilterOutRe=^/${opt_workdir}/",);my @ws = $search->search($opt_workdir);my @dir = $search->search($opt_dir);## Scan for a source file# Trying to detect empty views# Look for file, not directory# Keep a count for reporting#{foreach ( @ws ){$filesBase++ unless ( m~/$~ );}my $fileFound = 0;foreach ( @dir ){next if ( m~/$~ );$fileFound = 1;last;}unless ( $fileFound ){Warning ("No source files found in source view");$opr_done = 1;return;}}#Information ("WS Results", @ws);#Information ("DIR Results", @dir);#Information ("WS Results: ", scalar @ws);#Information ("DIR Results:", scalar @dir);## Create a hash the Workspace and the User dir# The key will be file names#my %ws; map ( $ws{$_} = 1 , @ws );my %dir; map ( $dir{$_} = 1 , @dir );## Create hash of paths to persist# build/* -> Persist directory. Keep dir tree if not# being imported, otherwise delete.#my %persistPaths;if ( $opt_mergePaths ){foreach ( split(',', $opt_mergePaths) ){if ( m~(.+/)\*$~ ){my $base = $1;$persistPaths{$base} = 1 unless( exists $dir{$base});}}Verbose0("Persist Paths:" , sort keys %persistPaths);}## Create a hash of common elements# Removing then from the other two#my %common;foreach ( keys %ws ){next unless ( exists $dir{$_} );$common{$_} = 1;delete $ws{$_};delete $dir{$_};}## Now have:# %ws - Hash of paths that are only in the Workspace# %dir - Hash of paths that are only in New Import# %common - Hash of paths that are common to both##DebugDumpData( 'WS', \%ws );#DebugDumpData( 'DIR', \%dir );#DebugDumpData( 'COMMON', \%common );## Need to consider the case where a file has been replaced with a directory# and visa-versa. Delete files and directories first.### Remove files# Sort in reverse. This will ensure that we process directory# contents before directories#my @rm_files = reverse sort keys %ws;if ( @rm_files ){## Calculate new top level paths# These are of the form xxxxx/#my @newTldPaths;if ( $opt_mergePaths ){foreach (@rm_files){push (@newTldPaths, $1 ) if ( m~^([^/]+)/$~ );}}my @processedFiles;foreach my $file ( @rm_files ){## Detect items that are to be retained# Do not delete items that are a part of a top level path that# are not present in the New Import#if ( $opt_mergePaths ){my $keep = 0;#### Following removed because it did the wrong thing and I'm not too sure## under what conditions its needed.## It did the wrong thing when used with '++,XXXX/**'## Perhaps its only these that cause problems####foreach ( @newTldPaths )##{## if ( $file =~ m~^$_/~ )## {## Verbose("Merge Retain(0): $file, $_");## $keep = 1;## last;## }##}if ( $file =~ m~(^.*/)~ ){my $tpath = $1;foreach ( keys %persistPaths){if ( $file =~ m~^$_~ ){Verbose0("Merge Retain(1): $file");$keep = 1;last;}}}## Examine $opt_mergPaths and process entries that look like# build/** -> keep the directory and every think under it# build/* -> Persist directory. Keep dir tree if not# being imported, otherwise delete.#foreach ( split(',', $opt_mergePaths) ){if ( m~(.+/)\*\*$~ ){my $base = $1;if ( $file =~ m~^$base~ ){Verbose0("Merge Retain(2): $file");$keep = 1;last;}}}next if ($keep);}Verbose0("Removing $file");$filesDeleted++ unless ( $file =~ m~/$~ );$dirsDeleted++ if ( $file =~ m~/$~ );unlink "$opt_workdir/$file";push @processedFiles, $file;}@rm_files = @processedFiles;## Inform Subversion about the removed files#my $base = 0;my $num = $#rm_files;Message ("Update the workspace: Removed $filesDeleted Files, $dirsDeleted directories");while ( $base <= $num ){my $end = $base + 200;$end = $num if ( $end > $num );$svn->SvnCmd ( 'delete', map ("$opt_workdir/$_@", @rm_files[$base .. $end] ),{ 'error' => 'Deleting files from workspace' } );$base = $end + 1;}}## Add New Files# Won't add empty directories at this point## Process by sorted list# This will ensure we process parent directories first#my @added = sort keys %dir;if ( @added ){my @processedFiles;foreach my $file ( @added ){## Detect items that are to be merged# Only specified top level paths are to be imported# Special mergePath names# ++ - All files and directories# + - All files in the root# path/** - Keep all items under path# Otherwise - name of a directory#if ( $opt_mergePaths ){my $discard = 1;foreach ( split(',', $opt_mergePaths) ){next if ( m ~\*\*$~ );if ( $_ eq '++' ){$discard = 0;last;}elsif ( $_ eq '+' ){if ( ($file =~ tr~/~/~) eq 0 ){$discard = 0;last;}}elsif ( $file =~ m~^$_/~ ){$discard = 0;last;}}Verbose0("Not Importing: $file") if ( $discard ) ;next if ( $discard );}my $src = "$opt_dir/$file";my $target = "$opt_workdir/$file";$filesAdded++ unless ( $file =~ m~/$~ );$dirsAdded++ if ( $file =~ m~/$~ );push @processedFiles, $file;if ( -d $src ){Verbose0("Adding directory: $file");mkdir ( $target ) unless (-d $target);}else{my $path = dirname ( $target);mkdir ( $path ) unless (-d $path);Verbose0("Adding $file");unless (File::Copy::copy( $src, $target )){Error("Failed to transfer file [$file]: $!");}}}@added = @processedFiles;## Inform Subversion about the added files# The command line does have a finite length, so add them 200 at a# time.#my $base = 0;my $num = $#added;Message ("Update the workspace: Added $filesAdded Files, $dirsAdded directories");while ( $base <= $num ){my $end = $base + 200;$end = $num if ( $end > $num );$svn->SvnCmd ( 'add', '--depth=empty', '--parents', map ("$opt_workdir/$_@", @added[$base .. $end] ),{ 'error' => 'Adding files to workspace' } );$base = $end + 1;}}## The common files may have changed# Simply copy them all in and let subversion figure it out#foreach my $file ( sort keys %common ){my $src = "$opt_dir/$file";my $target = "$opt_workdir/$file";$filesTransferred++ unless ( $file =~ m~/$~ );$dirsTransferred++ if ( $file =~ m~/$~ );next if ( -d $src );if ( File::Compare::compare ($src, $target) ){Verbose ("Transfer $file");unlink $target;unless (File::Copy::copy( $src, $target )){Error("Failed to transfer file [$file]: $!","Src: $src","Tgt: $target");}}}Message ("Update the workspace: Transferred $filesTransferred Files, $dirsTransferred directories")if ($filesTransferred);## Commit the workspace# This will go back onto the trunk#if ( $opt_commit ){$svn = NewSessionByWS( $opt_workdir );my $pkgPath = $svn->Path();my $ciComment = "$pkgPath: Checkin by Svn Import";$ciComment .= "\n" . $opt_log if ( $opt_log );$ciComment =~ s~\r\n~\n~g;$ciComment =~ s~\r~\n~g;$ciComment = encode('UTF-8', $ciComment, Encode::FB_DEFAULT);$svn->SvnCi ('comment' => $ciComment, 'allowSame' => 1 );Message ("Repository Ref: " . $svn->RmRef) unless( $opt_label );unless ($svn->{NoRepoChanges}) {$svn->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));$svn->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));}## Label the result# The workspace will have been updated, so we can use it as the base for# the labeling process#if ( $opt_label ){my $tagComment = "$pkgPath: Tagged by Jats Svn Import";if ($svn->{NoRepoChanges} && $opt_log ){$tagComment .= "\nNo Repository changes on last commit. Comment was:";$tagComment .= "\n" . $opt_log;$tagComment =~ s~\r\n~\n~g;$tagComment =~ s~\r~\n~g;$tagComment = encode('UTF-8', $tagComment, Encode::FB_DEFAULT);}$svn->SvnCopyWs (target => $url_label,'noswitch' => 1,'replace' => $opt_replace,'comment' => $tagComment,);Message ("Repository Ref: " . $svn->RmRef);Message ("Vcs Tag : " . $svn->SvnTag);$svn->setRepoProperty('svn:author', $opt_author) if (defined ($opt_author));$svn->setRepoProperty('svn:date', $opt_date) if (defined ($opt_date));}}else{Message ("Workspace not commited","Workspace: $opt_workdir");}## Clean up#if ( $opt_delete && ! $opt_reuse && $opt_commit ){Message ("Delete Workspace");rmtree( $opt_workdir );}## Automation data transfer#if ( defined $opt_datafile ){my $data = JatsProperties::New();$data->setProperty('Command' , 'ImportPackage');$data->setProperty('Label' , $opt_label);$data->setProperty('subversion.url' , $svn->RmRef);$data->setProperty('subversion.tag' , $svn->SvnTag);$data->setProperty('files.base' , $filesBase);$data->setProperty('files.removed' , $filesDeleted);$data->setProperty('files.added' , $filesAdded);$data->Dump('InfoFile') if ($opt_verbose);$data->store( $opt_datafile );}$opr_done = 1;}#-------------------------------------------------------------------------------# Function : DeleteBranch## Description : Delete the branch that a workspace is based upon## Inputs :## Returns :#sub DeleteBranch{my $opt_path;my $opt_error = 0;## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"path:s" => \$opt_path,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Delete Branch") if ($opt_help);## Sanity Tests#Message ("Delete Workspace Branchs" );## Do all the hard work#$opt_path = '.' unless ( defined $opt_path );my $uref = NewSessionByWS($opt_path, 0, 1);my $ws_root = $uref->SvnLocateWsRoot(1);my $ws_url = $uref->FullWs();## What we do depends what arguments the user provided#unless ( @ARGV ){## If no branch was specified - then display the workspace branch#Error ('The workspace is not based on a branch')unless ( $ws_url =~ m ~/branches/(.*)~ );Message('The workspace is based on the branch: '. $1);}else{## Delete all specified branches#foreach my $branch ( @ARGV ){Message ("Deleting: " . $branch );my $target = join( '/', $uref->FullPath(), 'branches', $branch);if ( $uref->SvnDelete ('target' => $target,'comment' => [$uref->Path().": Delete Branch",'Deleted by user command: jats svn delete-branch'],'noerror' => 1,)){Warning ("Branch deletion failed: $branch");}}}$opr_done = 1;}#-------------------------------------------------------------------------------# Function : CreateBranch## Description : Branch a workspace and then switch to the new branch## Inputs :## Returns :#sub CreateBranch{my $opt_path;my $opt_comment;my $opt_switch = 1;my $opt_branch;## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"path:s" => \$opt_path,"switch!" => \$opt_switch,"comment:s" => \$opt_comment,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Create Branch") if ($opt_help);## Sanity Tests#Message ("Create Workspace Branch" );Error ("Too many arguments: @ARGV") if ( $#ARGV > 0 );Error ("Not enough arguments. No branch name specified") if ( $#ARGV < 0 );## Sanity test the label#$opt_branch = SvnIsaSimpleLabel ($ARGV[0] );## Do all the hard work#$opt_path = '.' unless ( defined $opt_path );my $uref = NewSessionByWS($opt_path, 0, 1);my $ws_root = $uref->SvnLocateWsRoot(1);my $ws_url = $uref->Full();## Use the version of the branch that has been committed as the base of the# copy. If the user has modified files, then they won't be committed## This operation will be server-side only#Message ("Creating branch: $opt_branch");my $repoLink = $uref->{InfoWs}{URL} . '@' . $uref->{InfoWs}{Revision};$uref->{DEVBRANCH} = join ('/', 'branches', $opt_branch);my $branch_tag = $uref->SvnCopy ('old' => $repoLink,'new' => join ('/', $ws_url, $uref->{DEVBRANCH} ),'comment' => $opt_comment ? $opt_comment : ('Created by Jats svn branch:' . $opt_branch),'replace' => 0,'parents' => 1,);if ( $opt_switch ){Verbose ("Switching to new branch: $opt_branch");$branch_tag = SvnPath2Url($branch_tag);chdir ($ws_root) || Error ("Cannot cd to: " .$ws_root);$uref->SvnSwitch ($branch_tag, $opt_path, '--Print', '--KeepWs' );}else{Warning ("Using existing workspace, not the created branch");}Message ("Repository Ref: " . $uref->RmRef);Message ("Vcs Tag : " . $uref->SvnTag);# ## # The copy operation *should* be a server side operation only# # If the user has committed changes, but not yet updated the local# # workspace, then subversion will do a client side copy# # This is not good.# ## $uref->SvnCopyWs (# target => join ('/', $ws_url, 'branches', $opt_branch),# 'allowLocalMods' => 1,# 'noupdatecheck' => 1,# 'noswitch' => ! $opt_switch,# 'replace' => 0,# 'comment' => $opt_comment ? $opt_comment : ('Created by Jats svn branch:' . $opt_branch),# );## Message ("Repository Ref: " . $uref->RmRef);# Message ("Vcs Tag : " . $uref->SvnTag);$opr_done = 1;}#-------------------------------------------------------------------------------# Function : SwitchBranch## Description : Switch to a specified branch## Inputs :## Returns :#sub SwitchBranch{my $opt_path = '.';my $opt_branch;## Parse more options#GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"path:s" => \$opt_path,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Switch Branch") if ($opt_help);return ShowBranches($opt_path) if ( $#ARGV < 0 );## Sanity Tests#Error ("Too many arguments: @ARGV") if ( $#ARGV > 0 );## Calculate the target name# trunk is special# tags/... is special$opt_branch = $ARGV[0];if ( $opt_branch eq 'trunk' ) {} elsif ( $opt_branch =~ m~tags/.+~ ) {} else {$opt_branch = join ('/', 'branches', $opt_branch);}Message ("Switching to new branch: $opt_branch");## Do all the hard work#my $uref = NewSessionByWS($opt_path, 0, 1);my $ws_root = $uref->SvnLocateWsRoot(1);my $ws_url = $uref->Full();my $branch_tag = join ('/', $ws_url, $opt_branch);## Validate the branch#$uref->SvnValidateTarget ('cmd' => 'svn switch','target' => $branch_tag,'require' => 1,);## Must Change directory before we switch# Otherwise we will import changes into the wrong place#chdir ($ws_root) || Error ("Cannot cd to: " . $ws_root);$uref->SvnSwitch ($branch_tag, $opt_path, '--Print', '--KeepWs' );$opr_done = 1;}#-------------------------------------------------------------------------------# Function : SvnMerge## Description : Perform an svn merge# - with sanity checking# - auto deterine the correct 'head' to merge from### Inputs : None## Returns :#sub SvnMerge{my $opt_path = '.';my $opt_info;my @mergeOpts;my $opt_dryRun;## Parse more options#Getopt::Long::Configure('pass_through');GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"path:s" => \$opt_path,'info' => \$opt_info,'dry-run' => \$opt_dryRun,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Sync Merge") if ($opt_help);## Save merge options# Error if a non-option is present#foreach (@ARGV) {if (m~^-~) {push @mergeOpts, $_;} else {Error ("Only options must be passed to Merge: $_");}}## We intercepted the dry-run option# Put the option back into the stream.if ($opt_dryRun) {push @mergeOpts, '--dry-run';}# Check we are in a workspace# Create an SVN session#my $uref = NewSessionByWS($opt_path, 0, 1);# DebugDumpData("uref", $uref);## Warn user if the command is being executed from within a subdirectory of the workspace# It might work, but if the directory is deleted it will go badly#my $ws_root = mustBeWsRoot($uref);## Determine the source of the merge# Get some more workspace information#$uref->getWsExtraInfo();my $logInfo = $uref->{InfoWsExtra};#DebugDumpData("getWsExtraInfo", $logInfo);# A bit of sanity testingError("Workspace does not appear to be a branch") unless (exists $logInfo->{'copyfrom-path'});Error("Workspace does not appear to be a branch") unless (exists $logInfo->{'target'});Error("Workspace is a trunk") if ($logInfo->{'target'} =~ m~/trunk$~);Error("Workspace is a raw branch") if ($logInfo->{'target'} =~ m~/branches$~);Error("Workspace is a raw tag") if ($logInfo->{'target'} =~ m~/tags$~);Error("Workspace is a within a tag") if ($logInfo->{'target'} =~ m~/tags/~);# Ensure the source is a branch and not a trunk# Ensure this workspace is not on the same bit (trunk or branch)#Message ("Merge Info - No merge performed") if $opt_info;Message ("RepoRoot: " . $uref->{InfoWs}{'Repository Root'});Message ("Parent: " . $logInfo->{'copyfrom-path'});Message ("Workspace: " . $logInfo->{'target'});unless ($opt_info) {## $logInfo->{'copyfrom-path'} is the parent of the branch in the workspace# use merge ^/<copyfrom-path> to merge the data into this workspace## Perform an interactive command so that the user can accept conflicts - if they wantmy $rv = SvnUserCmd( 'merge',@mergeOpts,'^' . $logInfo->{'copyfrom-path'},$opt_path,{ 'credentials' => 1 });exit $rv;}$opr_done = 1;}#-------------------------------------------------------------------------------# Function : SvnReintegrate## Description : Simulate an svn merge --reintegrate (which is now deprecated)# - Assume the user has the 'trunk' in a workspace# - Ensure there are no uncommitted files# - Ensure it is upto date with thr REpo server# - with much sanity checking# - verify the named branch# - Ensure the named branch is derived from the workspace# - perform a simple merge## Inputs : None## Returns :#sub SvnReintegrate{my $opt_path = '.';my $opt_info;my @mergeOpts;my $opt_reintegrate;my $opt_dryRun;my $opt_branch;## Parse more options#Getopt::Long::Configure('pass_through');GetOptions ("help:+" => \$opt_help,"manual:3" => \$opt_help,"path:s" => \$opt_path,'info' => \$opt_info,'reintegrate!' => \$opt_reintegrate,'dry-run' => \$opt_dryRun,'branch:s' => \$opt_branch,) || Error ("Invalid command line" );## Subcommand specific help#SubCommandHelp( $opt_help, "Reintegrate Merge") if ($opt_help);## Save merge options# Extract the named branch ( if not provided via the -branch ) option#foreach (@ARGV) {if (m~^-~) {push @mergeOpts, $_;} else {Error ("Source branh for the merge must only be specified once") if (defined($opt_branch));$opt_branch = $_;}}Error("No branch specified") unless defined $opt_branch;Error("Branch name looks bad") unless ($opt_branch =~ m~[-/a-zA-Z0-9]~i);## We intercepted the dry-run option,# Put the option back into the stream.if ($opt_dryRun) {push @mergeOpts, '--dry-run';}## Calculate the target name# trunk is special# tags/... is specialif ( $opt_branch eq 'trunk' ) {} elsif ( $opt_branch =~ m~tags/.+~ ) {} else {$opt_branch = join ('/', 'branches', $opt_branch);}## Check we are in a workspace# Create an SVN session#my $uref = NewSessionByWS($opt_path, 0, 1);$uref->{WSURL} =~ m~[^/](/.*)~;$uref->{target} = $1;## Warn user if the command is being executed from within a subdirectory of the workspace# It might work, but if the directory is deleted it will go badly#my $ws_root = mustBeWsRoot($uref);#DebugDumpData("uref", $uref);## Validate the branch the user has specified - it must exist#my $ws_url = $uref->Full();my $branch_tag = join ('/', $ws_url, $opt_branch);$uref->SvnValidateTarget ('cmd' => 'svn reintegrate','target' => $branch_tag,'require' => 1,);## Verify the source of the merge# Need to get data about the branch, not the current workspace#my $branchRef = NewSessionByUrl($branch_tag);$branchRef->getWsExtraInfo();my $branchLogInfo = $branchRef->{InfoWsExtra};#DebugDumpData("getWsExtraInfo", $branchLogInfo);# A bit of sanity testingError("Branch does not appear to be a branch") unless (exists $branchLogInfo->{'copyfrom-path'});Error("Branch does not appear to be a branch") unless (exists $branchLogInfo->{'target'});Warning("Branch is a trunk") if ($branchLogInfo->{'target'} =~ m~/trunk$~);Error("Branch is a raw branch") if ($branchLogInfo->{'target'} =~ m~/branches$~);Error("Branch is a raw tag") if ($branchLogInfo->{'target'} =~ m~/tags$~);Warning("Branch is a within a tag") if ($branchLogInfo->{'target'} =~ m~/tags/~);Error ("Merging to myself") if ($uref->{target} eq $branchLogInfo->{'target'});Error ("Branch not taken from this trunk", "Workspace: $uref->{'target'}","Branch: $branchLogInfo->{'copyfrom-path'}") unless ($uref->{'target'} eq $branchLogInfo->{'copyfrom-path'});Message ("Reintegrate Info - No merge performed") if ($opt_info );Message ("RepoRoot: " . $uref->{InfoWs}{'Repository Root'});Message ("Source Branch: " . $branchLogInfo->{'target'});Message ("Workspace Branch: " . $uref->{'target'} );Message ("Reintegrate from $branchLogInfo->{'target'} to $uref->{'target'}");## Examine the workspace and ensure that there are no modified# files - unless they are expected## Prevent the user from merging into a WS that has not been committed#$uref->SvnWsModified ( 'cmd' => 'Reintegrate' );unless ($opt_info) {## $branchLogInfo->{'target'} is the branch of the specified branch# $uref->{target} - should be the same## use merge ^/<target> to merge the data into this workspace## Perform an interactive command so that the user can accept conflicts - if they want#my $rv = SvnUserCmd( 'merge', '--reintegrate',@mergeOpts,'^' . $branchLogInfo->{'target'},'.',{ 'credentials' => 1 });}$opr_done = 1;}#-------------------------------------------------------------------------------# Function : mustBeWsRoot## Description : Ensure that the user is not in a subdirectory of a workspace## Inputs : $uref - A Svn session handle## Returns : Will not return on error# Return the workspace root as provided by SvnLocateWsRoot#sub mustBeWsRoot{my ($uref) = @_;my $ws_root = $uref->SvnLocateWsRoot(0);my $pathToRoot = RelPath($ws_root);if ( $pathToRoot =~ m~^..~) {Error("This command cannot be executed within a subdirectory of the workspace","It can be executed in the root of the workspace: $pathToRoot","It can be executed externally with the -path option");}return $ws_root;}#-------------------------------------------------------------------------------# Function : ShowBranches## Description : Show branches in current workspace# Internal use only## Inputs : $opt_path - Optional path## Returns :#sub ShowBranches{my ($opt_path) = @_;my $uref = NewSessionByWS($opt_path, 0, 1);my $ws_url = $uref->Full();## Display the packages full URL - allow the user to manually look at more# List the branches#Message ("Url: $ws_url", 'Available Branches');SvnUserCmd( 'ls', join ('/', $ws_url, 'branches'), { 'credentials' => 1 });$opr_done = 1;}#-------------------------------------------------------------------------------# Function : SubCommandHelp## Description : Provide help on a subcommand## Inputs : $help_level - Help Level 1,2,3# $topic - Topic Name## Returns : This function does not return#sub SubCommandHelp{my ($help_level, $topic) = @_;my @sections;## Spell out the section we want to display## Note:# Due to bug in pod2usage can't use 'head1' by itself# Each one needs a subsection.#push @sections, qw( NAME SYNOPSIS ) ;push @sections, qw( ARGUMENTS OPTIONS ) if ( $help_level > 1 );push @sections, qw( DESCRIPTION ) if ( $help_level > 2 );## Extract section from the POD#pod2usage({-verbose => 99,-noperldoc => 1,-sections => $topic . '/' . join('|', @sections) } );}#-------------------------------------------------------------------------------# Documentation# NOTE## Each subcommand MUST have# head1 section as used by the subcommand# This should be empty, as the contents will NOT be displayed# head2 sections called# NAME SYNOPSIS ARGUMENTS OPTIONS DESCRIPTION##=head1 xxxxxx#=head2 NAME#=head2 SYNOPSIS#=head2 ARGUMENTS#=head2 OPTIONS#=head2 DESCRIPTION#=pod=for htmltoc GENERAL::Subversion::=head1 NAMEjats svn - Miscellaneous SubVersion Operations=head1 SYNOPSISjats svn [options] command [command options]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operationCommon Command Options:All command support suboptions to provide command specific help-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]Commands are:test - Test access to subversionpaths - Display Subversion tag to URL conversionsls URL - List Repo contents for URLtag [URL] - Convert URL or Path to a Release Manager Tagurl [TAG] - Convert TAG or Path to a Subversion URLcreate-package URL - Create a new package at URLdelete-package URL - Delete Package Subtreebranch BRANCH - Create a Development Branchswitch [BRANCH] - Switch to a Development Branchdelete-branch - Delete a Development Branchimport URL - Import files to package at URLmerge - Merge head into a feature branchreintegrate - Integrate a feature branch to its headUse the commandjats svn command -hfor command specific help=head1 OPTIONS=over=item B<-help[=n]>Print a help message and exit. The level of help may be either 1, 2 or3 for a full manual.This option may be specified multiple times to increment the help level, orthe help level may be directly specified as a number.=item B<-man>This is the same as '-help=3'.The complete help is produced in a man page format.=item B<-verbose[=n]>This option will increase the level of verbosity of the commands.If an argument is provided, then it will be used to set the level, otherwise theexisting level will be incremented. This option may be specified multiple times.=back=head1 DESCRIPTIONThis program provides a number of useful Subversion based operations.=head1 Test Subversion=head2 NAMETest Subversion=head2 SYNOPSISjats svn test=head2 DESCRIPTIONThis command will ensure that the subversion command line utility can belocated. The command will report the version of the svn client found.=head1 Subversion Paths=head2 NAMESubversion Paths=head2 SYNOPSISjats svn paths=head2 DESCRIPTIONThis command will display the base Tags and associated URLs that are used byJATS to convert a 'Subversion Tag' into a full URLs that will be used to accessa physical repository.The 'Tags' configuration is site-specific.=head1 List Repository=head2 NAMEList Repository=head2 SYNOPSISjats svn ls <URL>=head2 DESCRIPTIONThis command will take a URL and perform a 'svn' list operation. The URL willbe expanded to include the site specific repository.=head1 Url to Tag=head2 NAMEUrl to Tag=head2 SYNOPSISjats svn tag [Option] [tag]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-path=path - Convert specified path-url=url - Convert specified URL=head2 DESCRIPTIONThis command will convert a URL or a PATH to a Subversion Tag that canbe used within the remainder of the build system. If no PATH or URL is provided,then the command uses a path of the current directory.The command will convert either a PATH or a URL. It will not do both.The command will use the configured Subversion URL prefixes to create the Tag.If a PATH is to be converted, then the PATH must address a Subversion workspace.The conversion will return a Tag to the root of the Workspace and Peg it tothe last committed version. The command will not determine if the workspacecontains modified files.If a URL is to be converted, then the resultant value should be used withcaution. The result is only as good as the provided URL and may not addressthe root of a package.=head1 Tag to Url=head2 NAMETag to Url=head2 SYNOPSISjats svn url [Option] [url]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-path=path - Convert specified path-url=url - Convert specified URL=head2 DESCRIPTIONThis command will convert a TAG or a PATH to a full URL that can be useddirectly by Subversion. If no PATH or TAG is provided, then the command uses apath of the current directory.The command will convert either a TAG or a PATH. It will not do both.The command will use the configured Subversion URL prefixes to expand the TAG.If a PATH is to be converted, then the PATH must address a Subversion workspace.The conversion will return a URL to the root of the Workspace and Peg it tothe last committed version. The command will not determine if the workspacecontains modified files.If a TAG is to be converted, then the resultant value should be used withcaution. The result is only as good as the provided URL and may not addressthe root of a package.=head3 ExamplesTo display the URL of the current workspacejats svn urlTo display the URL of a known workspacejats svn url -path=myWorkSpaceTo convert a TAG from Release Manager or other JATS commandsjats svn url AUPERASVN01/COTSjats svn url SVN::AUPERASVN01/COTS/bouncycastle/trunk::bouncycastle_1.3.1.cots@502=head1 Create a Package Version=head2 NAMECreate a Package Version=head2 SYNOPSISjats svn [options] create-package URL [command options]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operationCommand Options-help[=n] - Provide command specific help-new - Package must not exist-replace - Replace any existing versions-import=path - Import directory tree-label=nnn - Label imported package-trunk - Import to trunk (default)-tags=nnn - Import to tags-branch=nnn - Import to branches=head2 ARGUMENTSThe command takes one argument: The URL of the desired package.This may be be:=over=item * A full URLComplete with protocol and path information.=item * A simple URLJATS will prepend the site-specific repository location to the user provided URL=back=head2 OPTIONS=over=item -help[=n]Print a help message and exit. The level of help may be either 1, 2 or 3.This option may be specified multiple times to increment the help level, orthe help level may be directly specified as a number.=item -newThis option specifies that the named package MUST not exist at all.=item -replaceThis option allows the program to replace any existing versions of theimported source. It will allow the deletion of any existing trunk, tags orbranches.=item -import=pathThis option specifies the path of a subdirectory tree to import into the newlycreated package. In not provided, then only a package skeleton will be created.All files and directories below, but not including, the named path will beimported into the package.The imported directory tree will be scanned to ensure that the following subdirectoriesdo not exist: .svn, .hg, .git, .cvs, tags, trunk and branches. These directories areeither reserved or indicative that the import tree is already version controlled.=item -label=nnnThis option specifies a label to place the imported source.=item -trunkThis option specifies that imported source will be placed on the trunk of thepackage. This is the default mode of import.The options -trunk, -tags and -branch are mutually exclusive.=item -tags=nnnThis option specifies that imported source will be placed directly on thenamed tag of the package.The options -trunk, -tags and -branch are mutually exclusive.=item -branch=nnnThis option specifies that imported source will be placed directly on thenamed branch of the package.The options -trunk, -tags and -branch are mutually exclusive.=back=head2 DESCRIPTIONThis command will create a new package within a repository. It will ensurethat the package contains the three required subdirectories: trunk, tags andbranches.The command will also ensure that packages are not placed at inappropriatelocations within the repository. It is not correct to place a package withinanother package.The command will, optionally, import a directory tree into the repository and,optionally, label the package.The package body may be imported to the 'trunk' or to a branch or a tag.By default the data will be imported to the trunk and may be labeled (tagged).Options allow the targets to be deleted if they exist or to ensure that theyare not present.The command does not attempt to merge file versions within the repository. Itmay result in multiple instances of a file within the repository. Use only forsimple imports. Use the 'import' command for more sophisticated import requirements.=head3 ExamplesTo create a package skeleton in the Perth MREF_Package repository for a packagecalled 'VIXmyPackage':jats svn create-package AUPERASVN01/MREF_Package/VIXmyPackageTo create a package skeleton in the Perth MREF_Package repository, import codeinto the trunk of the package and label (tag) it:jats svn create-package \AUPERASVN01/MREF_Package/VIXmyPackage \-import=VIXmyNewPackage \-label=VIXmyPackage.WIP=head1 Delete a Package=head2 NAMEDelete a Package=head2 SYNOPSISjats svn delete-package URL [options]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operation=head2 ARGUMENTSThe command takes one argument: The URL of the desired package.This may be be:=over=item * A full URLComplete with protocol and path information.=item * A simple URLJATS will prepend the site-specific repository location to the user provided URL=back=head2 OPTIONSThis command has no significant options, other than the general help options.=head2 DESCRIPTIONThis command will delete a package from the repository. It will ensurethat the package is a valid package, before it is deleted.The command is intended to be used by test scripts, rather than users.=head1 Create Branch=head2 NAMECreate a Workspace Branch=head2 SYNOPSISjats svn branch branch-name [options]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operation-path=path - Target workspace-[no]switch - Switch to new branch(default)-comment=text - Comment to apply to the new branch=head2 ARGUMENTSThe command takes one argument. The name of the branch to be created.=head2 OPTIONS=over=item B<-path=path>This options specifies the path of the target workspace. If not provided thecommand will use the current directory.=item B<-[no]switch>If enabled (the default) the workspace will be switched to the new branch atthe end of the process.=item B<-comment=text>If present, the specified text will be used as a Subversion comment when thebranch is created.If not provided, then JATS will provide a basic comment.=back=head2 DESCRIPTIONThis command will create a named branch associated with the workspace in thespecified path. It is intended to simplify the creation of Private orDevelopment branches.If the named branch already exists, then the command will fail.The command performs a server-side copy. It will not commit any locallymodified files. Nor will it inform you if there are any.By default, the user is 'switched' to the newly created branch.=head1 Switch Branch=head2 NAMESwitch a Workspace Branch=head2 SYNOPSISjats svn switch [branch-name] [options]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operation-path=path - Target workspace=head2 ARGUMENTSThe command takes one optional argument. The name of the target branch.=head2 OPTIONS=over=item B<-path=path>This options specifies the path of the target workspace. If not provided thecommand will use the current directory.=back=head2 DESCRIPTIONThis command will switch the users workspace to the named branch. This isidentical to the Subversion switch command, except it is easier to user andhas several validity checks and other enhancements.The command has two modes of operation:=over 4=item 1. Display a list of branched in the current package.If no branch is specified, then the utility will display a list of branches inthe packages 'branches' directory.=item 2. Switch to the named branch.The named branch must exists otherwise the command will fail.There are two special variants of the branch name:=over 4=item trunkIf the branch is named 'trunk' then it will refer to the packages truck=item tagsIf the branch name starts with 'tags/', then the command will refer toa tag within the package and not a branch.=backThe command will add and remove unmodified files from the workspace during thisoperation.=back=head3 ExamplesTo switch to the packages trunkjats svn switch trunkTo switch to the a branch called MyBranchjats svn switch MyBranchTo switch to a tagged version of the packagejats svn switch tags/MyPackage_1.0.0000.crTo display a list of available branches (not tags)jats svn switch=head1 Delete Branch=head2 NAMEDelete the Workspace Branch=head2 SYNOPSISjats svn delete-branch [options] [branch-list]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operation-path=path - Target workspace=head2 ARGUMENTSThe command may take zero or more arguments. If provided the arguments will bebranch names to be deleted.=head2 OPTIONS=over=item B<-path=path>This options specifies the path of the target workspace. If not provided thecommand will use the current directory.=back=head2 DESCRIPTIONThis command can display the branch associated with the workspace or it candelete one or more branches. It is intended to simplify the deletion of Privateor Development branches.=over 4=item 1 Arguments are providedThe command will delete all the named branches. If a named branch does not existthen the command will issue a warning message.=item 2 No arguments providedThe command will display the branch associated with the workspaceIf the workspace is not linked to a 'branch' then the command will fail.=back=head1 Import directory to a Package=head2 NAMEImport directory to a Package=head2 SYNOPSISjats svn [options] import URL [command options]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operationCommand Options-help[=n] - Command specific help, [n=1,2,3]-verbose[=n] - Verbose operation-package=name - Name of source package-dir=path - Path to new version-label=label - Label the result-branch=branchName - Base import on a branch-replace - Allow the label to be replaced-reuse - Reuse the import directory-workspace=path - Path and name of alternate workspace-[no]delete - Deletes workspace after use. Default:yes-author=name - Force author of changes-date=dateString - Force date of changes-log=text - Append text to the commit message-datafile=path - Export tag data for automation-[no]commit - Prevent changes being committed. Default:Yes-printfiles=n - Control commit verbosity-mergePaths=dirList - Comma separated list of directories to merge=head2 ARGUMENTSThe command takes one argument: The URL of the desired package.This may be be:=over=item * A full URLComplete with protocol and path information.=item * A simple URLJATS will prepend the site-specific repository location to the user provided URL=back=head2 OPTIONS=over=item -help[=n]Print a help message and exit. The level of help may be either 1, 2 or 3.This option may be specified multiple times to increment the help level, orthe help level may be directly specified as a number.=item -verbose[=n]This option will increase the level of verbosity of the utility.If an argument is provided, then it will be used to set the level, otherwise theexisting level will be incremented. This option may be specified multiple times.=item -package=nameEither this option or a bare URL on the command line must be provided. Itspecifies the repository and package to be used as a basis for the work.=item -dir=pathThis option is mandatory. It specifies the path to a local directory thatcontains a version of the software to be checked in.=item -label=nameThe resulting software version will be labeled with this tag, if it is provided.A label name of TIMESTAMP will be treated in special manner. The name will bereplaced with a unique name based on the users name and the current date time.=item -branch=branchNameThis option will cause the importation to be referenced to the named branch.If the branch does not exist it will be created. If it does exist then it willbe used.If this option is not specified, then the importation will be based on the 'trunk'.If the Workspace is provided, then it will be used independently of this option.A branchName of TIMESTAMP will be treated in special manner. The name will bereplaced with a unique name based on the users name and the current date time.=item -replaceThis option, if provided, allows the label to be replaced.=item -reuseThis option can be used to speed the creation of multiple versions in a scriptedenvironment. The option allows the utility to reuse the workspace if it exists.=item -workspace=pathThis option specifies an alternate workspace directory to create and use. Thedefault directory is "SvnImportDir" within the users current directory.=item [no]deleteThis option control the deletion of the workspace directory. By default thedirectory will be deleted, unless re-use is also used.=item -author=nameThis option will force the author of changes as recorded in the repository.The repository must be configured to allow such changes.This option may not work for non-admin users.=item -date=dateStringThis option will force the date of the changes as recorded in the repository.The repository must be configured to allow such changes.The dateString is in a restricted ISO 8601 format: ie 2009-02-12T00:44:04.921324ZThis option may not work for non-admin users.=item -log=textThis option will append the specified text to the commit message.The first line of the commit message is fixed by the import tool.=item -datafile=pathThis option will cause the utility to create a data file to record the importtag. It is used for automation of the import process.=item -[no]commitThis option will prevent the final workspace from being committed to theRepository. This allows inspection of the results.The default operation is to commit and label the results of the import.=item -printfiles=nThis option controls commit verbosity. The default operation is to displaythe files added and removed during the commit.Suitable numbers are: None, 0 (No Display) and 1 (Full Display).=item -mergePaths=dirListThis option specifies a Comma separated list of directories to be mergedduring the import process. This works via the following mechanism:If the named directory exists in the 'new' image it will replace that in the'initial' workspace.If the named directory does not exist in the 'new' image, but does exist in the'initial' image then it will be retained in the 'final' image.Directories other than those named will not be imported.=back=head2 DESCRIPTIONImport a new version of a package to the trunk of the package. The utilitywill only import changed files so that file history is preserved within therepository.This utility is used import software from another version control systemThe utility will:=over=item *Create a Work Space based on the current package versionThe 'trunk' of the named package will be used as the base for the workspace,unless modified with the -branch option.=item *Update files and directoriesDetermines the files and directories that have been added and deleted andupdate the Workspace to reflect the new structure.=item *Check in the new version=item *Label the new version=back=head1 Sync Merge=head2 NAMEPerform a Feature Branch Sync Merge=head2 SYNOPSISjats svn merge [options]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operation-info - Displays merge info only-dry-run - Perform a dry run of the merge-path=path - Target workspace... - Other options are passed to the merge=head2 ARGUMENTSThe command takes no arguments, just options.=head2 OPTIONS=over=item B<-path=path>This options specifies the path of the target workspace. If not provided thecommand will use the current directory.=item B<-info>This option will display information about the proposed merge, but it will not do the merge.This is not the same as a '-dry-run' as it shows information that the command has recovered fromthe workspace.=item B<-dry-run>This option will perform a dry run of the actual merge. It will not modify the workspace.=item B<...>Options that are not processed by this command will be passed through to the underlying'svn merge' command. Available options include:=over 8=item * --accept=mf (mine-full)=item * --accept=mc (mine-conflict)=back=back=head2 DESCRIPTIONThis command implements the common operation of merging the release branchhead (normally trunk) onto a private development branch in the current working copy.The main goal of this command is to avoid situations where developers accidentally mergefrom the wrong branch, or end up with (to them) inexplicable merge failures and thuslose confidence in Subversion.It will fail if the current working copy is actually on the trunk, and not a branch.=head1 Reintegrate Merge=head2 NAMEReintegrate a Feature Branch=head2 SYNOPSISjats svn reintegrate [options] [branch name]Options:-help[=n] - Help message, [n=1,2,3]-man - Full documentation [-help=3]-verbose[=n] - Verbose command operation-path=path - Target workspace-info - Displays merge info only-dry-run - Perform a dry run of the merge-branch=name - The branch to be used as the merge source... - Other options are passed to the merge=head2 ARGUMENTSIf an argument is provided then it will be used as the name of the branch to be merged intothe current workspace. This is the same as using the -branch option.=head2 OPTIONS=over=item B<-path=path>This options specifies the path of the target workspace. If not provided thecommand will use the current directory.=item B<-info>This option will display information about the proposed merge, but it will not do the merge.This is not the same as a '--dry-run' as it shows information that the command has recovered fromthe workspace.=item B<-dry-run>This option will perform a dry run of the actual merge. It will NOT deleted the feature branch. It willswitch the workspace and after the dry run of the merge it will switch it back.This option implies '-reintegrate'.=item B<-branch>This option provides an alternate method for specifying the source of the merge.=item B<...>Options that are not processed by this command will be passed through to the underlying'svn merge' command. Available options include:=over 8=item * --accept=mf (mine-full)=item * --accept=mc (mine-conflict)=back=head2 DESCRIPTIONThis command implements the common operation of merging a private branch back into the maindevelopment branch (normally the trunk).The main goal of this command is to avoid situations where developers accidentally mergefrom the wrong branch, or end up with (to them) inexplicable merge failures and thuslose confidence in Subversion.It will fail if the specified branch was not tacken from the package's trunk.The command will do the following operations:=over 8=item *Ensure that the path address a subversion workspace and that the user is not in a sundirectoryof the workspace.=item *Ensure the specified branch exists within the package.=item *Ensure the workspace contains no modified files=item *Ensure that the specified branch was taken from the branch (often the trunk) on which theworkspace is based. A number of other sanity checks are also performed=item *Perform the reintegration merge.This is, strictly speaking a 'svn merge --reintegrate' as that operation has been deprecatedand was problematic. The effect is the same.=backAt the end of the reintegration merge the workspace will conatin modified files. The user should verifythat the merge has had the desired result and to commit the changes.=cut