Differences between revisions 4 and 5
Revision 4 as of 2008-02-20 20:00:45
Size: 26254
Editor: nat7
Comment:
Revision 5 as of 2008-02-20 20:49:16
Size: 25663
Editor: nat7
Comment:
Deletions are marked like this. Additions are marked like this.
Line 13: Line 13:
  .+ [[Replicating_An_Existing_Repository|Replicating An Existing Repository]]   .- Replicating An Existing Repository
Line 16: Line 16:
["Main"]
 .+ ["What Is Subversion For"]
 .+ ["Setting Up A Subversion Repository"]
 .+ ["SVNKit Architecture"]
 .+ ["Getting Started With SVNKit"]
 .+ ["Authentication"]
 .+ ["Managing Repository With SVNKit"]
  .+ ["Printing Out A Subversion Repository Tree"]
  .+ ["Printing Out File Contents"]
  .+ ["Printing Out Repository History"]
  .+ [:Committing To A Repository:Editing operation: committing to a repository]
  .+ [:Updating From A Repository:Editing Operation: receiving changes from a repository]
  .- Replicating An Existing Repository
  .+ ["Managing A Working Copy"]
Line 33: Line 18:
[[TableOfContents]] <<TableOfContents>>
Line 36: Line 21:
On the one hand '''SVNKit''' ver. 1.1 supports the Subversion ver. 1.4 feature of synchronizing two repositories. On a low-level
the [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html SVNRepository] class provides
a user [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html#replay(long,%20long,%20boolean,%20org.tmatesoft.svn.core.io.ISVNEditor) replay()] 
On the one hand [[SVNKit]] ver. 1.1 supports the Subversion ver. 1.4 feature of synchronizing two repositories. On a low-level
the [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html|SVNRepository]] class provides
a user [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html#replay(long,%20long,%20boolean,%20org.tmatesoft.svn.core.io.ISVNEditor)| replay()]]
Line 48: Line 33:
'''SVNKit''' ver. 1.1 also brings a high-level API to do synchronization just as the Subversion's '''svnsync''' utility does.
[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.java SVNAdminClient] provides such API methods as
* [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.html#doInitialize(org.tmatesoft.svn.core.SVNURL,%20org.tmatesoft.svn.core.SVNURL) doInitialize()], similar to {{{svnsync initialize}}} command
 * [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.html#doSynchronize(org.tmatesoft.svn.core.SVNURL) doSynchronize()], similar to {{{svnsync synchronize}}} command
 * [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.html#doCopyRevisionProperties(org.tmatesoft.svn.core.SVNURL,%20long) doCopyRevisionProperties()], similar to {{{svnsync copy-revprops}}} command
[[SVNKit]] ver. 1.1 also brings a high-level API to do synchronization just as the Subversion's '''svnsync''' utility does.
[[http://svnkit.com/k
b/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.java|SVNAdminClient]] provides such API methods as
 * [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.html#doInitialize(org.tmatesoft.svn.core.SVNURL,%20org.tmatesoft.svn.core.SVNURL)| doInitialize()]], similar to {{{svnsync initialize}}} command
 * [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.html#doSynchronize(org.tmatesoft.svn.core.SVNURL)|doSynchronize()]], similar to {{{svnsync synchronize}}} command
 * [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/wc/SVNAdminClient.html#doCopyRevisionProperties(org.tmatesoft.svn.core.SVNURL,%20long)|doCopyRevisionProperties()]], similar to {{{svnsync copy-revprops}}} command
Line 54: Line 39:
replicate a repository that is running under [http://apache.org Apache] or [http://svnbook.red-bean.com/nightly/en/svn.serverconfig.overview.html#svn.serverconfig.overview.svnserve svnserve] which don't support this functionality. In this case SVNKit provides its own feature that can replicate replicate a repository that is running under [[http://apache.org|Apache]] or [[http://svnbook.red-bean.com/nightly/en/svn.serverconfig.overview.html#svn.serverconfig.overview.svnserve|svnserve]] which don't support this functionality. In this case [[SVNKit]] provides its own feature that can replicate
Line 57: Line 42:
The [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/package-summary.html repository replicator] is a tool The [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/package-summary.html|repository replicator]] is a tool
Line 61: Line 46:
The replicator is represented by the class [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/SVNRepositoryReplicator.html SVNRepositoryReplicator]. The replicator is represented by the class [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/SVNRepositoryReplicator.html|SVNRepositoryReplicator]].
Line 65: Line 50:
attachment:Replicator_Diagram.png {{attachment:Replicator_Diagram.png}}
Line 78: Line 63:
Both source ({{{src}}}) and destination ({{{dst}}}) [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html SVNRepository] drivers must be created for Both source ({{{src}}}) and destination ({{{dst}}}) [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html|SVNRepository]] drivers must be created for
Line 119: Line 104:
passed to an instance of [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/SVNReplicationEditor.html SVNReplicationEditor]. passed to an instance of [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/SVNReplicationEditor.html|SVNReplicationEditor]].
Line 121: Line 106:
operation for the same particular revision on the source driver passing it a replication editor as an [:Updating From A Repository:update editor]. operation for the same particular revision on the source driver passing it a replication editor as an [[Updating_From_A_Repository|update editor]].
Line 125: Line 110:
[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/ISVNReplicationHandler.html SVNReplicationHandler] is introduced to control [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/replicator/ISVNReplicationHandler.html|SVNReplicationHandler]] is introduced to control
Line 134: Line 119:
To stop the replication process it's enough for the handler to throw an [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/SVNCancelException.html SVNCancelException] To stop the replication process it's enough for the handler to throw an [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/SVNCancelException.html|SVNCancelException]]
Line 379: Line 364:
First, we will try [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html#replay(long,%20long,%20boolean,%20org.tmatesoft.svn.core.io.ISVNEditor) replay()] First, we will try [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html#replay(long,%20long,%20boolean,%20org.tmatesoft.svn.core.io.ISVNEditor)| replay()]]
Line 439: Line 424:
we would like to use [http://tmate.org/svn/kb/javadoc/org/tmatesoft/svn/core/replicator/SVNRepositoryReplicator.html SVNRepositoryReplicator]: we would like to use [[http://tmate.org/svn/kb/javadoc/org/tmatesoft/svn/core/replicator/SVNRepositoryReplicator.html|SVNRepositoryReplicator]]:
Line 493: Line 478:
If the server does not support '''replay''' functionality we get [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/SVNErrorCode.html#RA_NOT_IMPLEMENTED SVNErrorCode.RA_NOT_IMPLEMENTED] and
invoke our replicator. {{{tgtRepository}}} is reinstantiated since it may be locked by its [http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html#getCommitEditor(java.lang.String,%20java.util.Map,%20boolean,%20org.tmatesoft.svn.core.io.ISVNWorkspaceMediator) getCommitEditor()] 
If the server does not support '''replay''' functionality we get [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/SVNErrorCode.html#RA_NOT_IMPLEMENTED|SVNErrorCode.RA_NOT_IMPLEMENTED]] and
invoke our replicator. {{{tgtRepository}}} is reinstantiated since it may be locked by its [[http://svnkit.com/kb/javadoc/org/tmatesoft/svn/core/io/SVNRepository.html#getCommitEditor(java.lang.String,%20java.util.Map,%20boolean,%20org.tmatesoft.svn.core.io.ISVNWorkspaceMediator)| getCommitEditor()]]
Line 551: Line 536:
Download the [http://svn.svnkit.com/repos/svnkit/trunk/doc/examples/src/org/tmatesoft/svn/examples/repository/Replicate.java example program source code]. Download the [[http://svn.svnkit.com/repos/svnkit/trunk/doc/examples/src/org/tmatesoft/svn/examples/repository/Replicate.java| example program source code]].

Main


Replicating an existing repository

On the one hand SVNKit ver. 1.1 supports the Subversion ver. 1.4 feature of synchronizing two repositories. On a low-level the SVNRepository class provides a user replay() method which accepts a client's commit editor to commit all changes made in a particular revision of the source repository to a target one:

   1     public abstract void replay( long lowRevision , long revision , boolean sendDeltas , ISVNEditor editor ) throws SVNException;

SVNKit ver. 1.1 also brings a high-level API to do synchronization just as the Subversion's svnsync utility does. SVNAdminClient provides such API methods as

For repositories accessible through the file:/// protocol or running under servers which support the replay functionality, this way of synchronizing two repositories should work well. But what if we would like to replicate a repository that is running under Apache or svnserve which don't support this functionality. In this case SVNKit provides its own feature that can replicate repositories running under older servers - repository replicator.

The repository replicator is a tool that gives you an ability to create clones of existing repositories. That is, the replicator copies revisions of existing repositories to other clean repositories what results in two separate repositories containing the same versioned data.

The replicator is represented by the class SVNRepositoryReplicator. Here's a lite class diagram demonstrating relationships between the replicator and other components which are involved by the replicator:

Replicator_Diagram.png

Repository replicator: replicating a range of source repository revisions

There are two ways you can replicate repositories. The first one corresponds to using the replicator's

   1     public long replicateRepository( SVNRepository src , SVNRepository dst , long fromRevision , long toRevision ) throws SVNException 

method.

Both source (src) and destination (dst) SVNRepository drivers must be created for the root locations of the source and destination repositories respectively. That is, only entire repository trees can be replicated, but not sub-trees. A destination repository must be either completely clean (be at revision 0) or must already contain all source repository revisions in the range starting from revision 1 and up to fromRevision - 1 inclusively. In all cases, if the destination repository latest revision is not equal to fromRevision - 1, you will get an exception.

If fromRevision is less or equal to 0, it automatically defaults to revision 1, since revision 0 is always a point of repository life start and doesn't contain any user valuable data. In all cases when toRevision is not in this range - toRevision > 0 and toRevision <  source repository latest revision - it automatically defaults to the source repository latest revision.

Repository replicator: Replicating a source repository incrementally

This way of replicator usage corresponds to using the replicator's

   1     public long replicateRepository( SVNRepository src , SVNRepository dst , boolean incremental ) throws SVNException 

method.

Incrementally means that sometime you replicated the source repository into the destination one, and since then have committed some more revisions into the source repository. Or maybe that time you replicated not the entire range of the source repository revisions. And in case you would also like to copy those revisions to the destination repository, you perform an incremental copy - copy those missing revisions. In fact, this method is equivalent to

   1     long fromRevision = incremental ? dst.getLatestRevision( ) + 1 : 1;
   2     return replicateRepository( src , dst , fromRevision , -1 );

That is, if you set incremental to false the whole source repository is replicated. Otherwise the source repository is incrementally copied up to the latest revision.

Repository replicator: replicating principles

Starting with the first revision to copy the replicator obtains information about all changed paths in the particular revision of the source repository. This information is analysed for the presence of paths copied in that revision. Then the replicator obtains a [:Committing To A Repository:commit editor] for the destination repository. This editor is passed to an instance of SVNReplicationEditor. A replication editor is like a bridge between the source and destination repositories: the replicator calls an update operation for the same particular revision on the source driver passing it a replication editor as an update editor. When the source driver calls the replication editor, the latter transforms these calls to calls to the commit editor of the destination driver. Thus changes received are redirected immediately to the destination repository.

SVNReplicationHandler is introduced to control replication process. At the start of each replication iteration the replicator checks the registered handler's method

   1     public void checkCancelled( ) throws SVNCancelException

To stop the replication process it's enough for the handler to throw an SVNCancelException exception. replicateRepository(...) method will throw it upper.

If replication is not cancelled and a log operation is successfully perfromed for a particular revision of the source repository, the replicator passes this log info to the registered handler's method

   1     public void revisionReplicating( SVNRepositoryReplicator source , SVNLogEntry logEntry ) throws SVNException

And after the current revision is successfully committed to the destination repository the replicaor passes commit info to the handler's method:

   1     public void revisionReplicated( SVNRepositoryReplicator source , SVNCommitInfo commitInfo ) throws SVNException;

The replicator copies both versioned and unversioned (revision properties) data.

In theory, with the repository replicator you are able to create exact copies of repository contents, but in practice it strongly depends on permissions you have on both source and destination repositories. Say, if you are not able to read some directory in the source repository, it is obvious that this directory will be missing in the destination one.

You can use different repository access [:SVNKit Architecture:protocols supported by SVNKit] for both source and destination repositories. This provides you an ability to make a local back-up of a repository located on the server machine.

Example: synchronizing/replicating a repository

In this example we will replicate a source repository to a local destination one. Our program should be able to receive two args: first one is the url of the source repository and the second one is the path of the target repository. If no args are provided, we create a local FSFS-type repository and fill it with some data. Here's a function which populates a repository with some dummy data.

   1     private static void populateSourceRepository( SVNRepository srcRepository ) throws SVNException {
   2         /*
   3          * Simple repository tree to create. Each entry will be 
   4          * added in its own revision.
   5          */
   6         String dirA = "dirA";
   7         String dirB = "dirA/dirB";
   8         String fileA = "dirA/fileA.txt";
   9         String fileB = "dirA/dirB/fileB.txt";
  10         byte[] fileAContents = "This is file fileA.txt".getBytes( );
  11         byte[] fileBContents = "This is file fileB.txt".getBytes( );
  12         SVNDeltaGenerator deltaGenerator = new SVNDeltaGenerator( );
  13         long revision = -1;
  14         SVNCommitInfo info = null;
  15         String checksum = null;
  16         
  17         /*
  18          * First commit "/dirA".
  19          */
  20         ISVNEditor editor = srcRepository.getCommitEditor( "adding " + dirA , null );
  21         editor.openRoot( -1 );
  22         editor.addDir( dirA , null , -1 );
  23         editor.closeDir( );
  24         editor.closeDir( );
  25         info = editor.closeEdit( );
  26         System.out.println( info );
  27         revision = info.getNewRevision( );
  28         
  29         /*
  30          * Then commit "/dirA/fileA.txt".
  31          */
  32         editor = srcRepository.getCommitEditor( "adding " + fileA , null );
  33         editor.openRoot( -1 );
  34         editor.openDir( dirA , revision );
  35         editor.addFile( fileA , null , -1 );
  36         editor.applyTextDelta( fileA , null );
  37         checksum = deltaGenerator.sendDelta( fileA , new ByteArrayInputStream( fileAContents ) , editor , true );
  38         editor.closeFile( fileA , checksum );
  39         editor.closeDir( );
  40         editor.closeDir( );
  41         info = editor.closeEdit( );
  42         System.out.println( info );
  43         revision = info.getNewRevision( );
  44 
  45         /*
  46          * Then commit "/dirA/dirB".
  47          */
  48         editor = srcRepository.getCommitEditor( "adding " + dirB , null );
  49         editor.openRoot( -1 );
  50         editor.openDir( dirA , revision );
  51         editor.addDir( dirB , null , -1 );
  52         editor.closeDir( );
  53         editor.closeDir( );
  54         editor.closeDir( );
  55         info = editor.closeEdit( );
  56         System.out.println( info );
  57         revision = info.getNewRevision( );
  58         
  59         /*
  60          * Then commit "/dirA/dirB/fileB.txt".
  61          */
  62         editor = srcRepository.getCommitEditor( "adding " + fileB , null );
  63         editor.openRoot( -1 );
  64         editor.openDir( dirA , revision );
  65         editor.openDir( dirB , revision );
  66         editor.addFile( fileB , null , -1 );
  67         editor.applyTextDelta( fileB , null );
  68         checksum = deltaGenerator.sendDelta( fileB , new ByteArrayInputStream( fileBContents ) , editor , true );
  69         editor.closeFile( fileB , checksum );
  70         editor.closeDir( );
  71         editor.closeDir( );
  72         editor.closeDir( );
  73         info = editor.closeEdit( );
  74         System.out.println( info );
  75     }

However if args are provided we must do some checks:

  • if the source url is a file:// url and there's no repository at this place, we also create a new one and fill it up with some data

  • if the source url is a file:// url and there's already a repository at this place and its latest revision is 0, we fill it with some data

  • in all other cases (non file:// access and empty repositories accessible through file://) we use the data from the source repository

   1 public class Replicate {
   2 
   3     public static void main( String[] args ) {
   4         /*
   5          * Default values:
   6          * source and target repository paths
   7          */
   8         String srcPath = "srcRepository";
   9         String tgtPath = "tgtRepository";
  10         String srcUrl = null;
  11         /*
  12          * Initializes the library (it must be done before ever using the
  13          * library itself)
  14          */
  15         setupLibrary( );
  16 
  17         if ( args != null ) {
  18             /*
  19              * a source repository url
  20              */
  21             srcUrl = ( args.length >= 1 ) ? args[0] : srcUrl;
  22             /*
  23              * a target repository path
  24              */
  25             tgtPath = ( args.length >= 2 ) ? args[1] : tgtPath;
  26         }
  27 
  28         SVNURL srcURL = null;
  29         SVNURL tgtURL = null;
  30         SVNRepository srcRepository = null;
  31         SVNRepository tgtRepository = null;
  32         boolean createSrcRepos = false;
  33         boolean populateSrcRepos = false;
  34         try {
  35             if ( srcUrl != null ) {
  36                 /*
  37                  * If a source url was provided, using it as a source repository
  38                  */
  39                 srcURL = SVNURL.parseURIDecoded( srcUrl );
  40                 if ( "file".equals( srcURL.getProtocol( ) ) ) {
  41                     File srcReposDir = new File( srcURL.getPath( ) );
  42                     if ( !srcReposDir.exists( ) ) {
  43                         /*
  44                          * it's a local access scheme and src path does not exist - 
  45                          * we'll need to create something
  46                          */
  47                         createSrcRepos = true;
  48                         populateSrcRepos = true;
  49                         srcPath = srcURL.getPath( );
  50                     } else {
  51                         srcRepository = SVNRepositoryFactory.create( srcURL );
  52                         if ( srcRepository.getLatestRevision( ) == 0 ) {
  53                             /*
  54                              * it's a local access scheme, src path already
  55                              * exists, but seems to be an empty repository - 
  56                              * we'll need to create something in it
  57                              */
  58                             populateSrcRepos = true;
  59                         }
  60                     }
  61                 }
  62             } else {
  63                 createSrcRepos = true;
  64                 populateSrcRepos = true;
  65             }
  66 
  67             if ( createSrcRepos ) {
  68                 srcURL = SVNRepositoryFactory.createLocalRepository( new File( srcPath ) , false , false );
  69             }
  70             
  71             /*
  72              * For the target repository we need to enable revision property 
  73              * changes. 
  74              */
  75             tgtURL = SVNRepositoryFactory.createLocalRepository(new File( tgtPath ) , true , false );
  76             
  77             srcRepository = SVNRepositoryFactory.create( srcURL );
  78             tgtRepository = SVNRepositoryFactory.create( tgtURL );
  79         } catch ( SVNException svne ) {
  80             /*
  81              * getFullMessage() will give us a full tree of SVNException 
  82              * errors.
  83              */
  84             System.err.println( "Can not create a repository: " + svne.getErrorMessage( ).getFullMessage( ) );
  85             System.exit( 1 );
  86         }
  87 
  88         /*
  89          * Deault auth manager is used to cache a username in the 
  90          * default Subversion credentials storage area.
  91          */
  92         srcRepository.setAuthenticationManager( SVNWCUtil.createDefaultAuthenticationManager( ) );
  93         tgtRepository.setAuthenticationManager( SVNWCUtil.createDefaultAuthenticationManager( ) );
  94         
  95         try{
  96             if ( populateSrcRepos ) {
  97                 /*
  98                  * Fills up the source repository with some data.
  99                  */
 100                 populateSourceRepository( srcRepository );
 101             }
 102             System.out.println( );
 103             long srcLatestRevision = srcRepository.getLatestRevision( );
 104             System.out.println( "The latest source revision: " + srcLatestRevision );
 105             System.out.println( );
 106             System.out.println( "'" + srcURL + "' repository tree:" );
 107             System.out.println( );
 108             /*
 109              * Using the DisplayRepositoryTree example to show the source 
 110              * repository tree in the latest revision. 
 111              */
 112             DisplayRepositoryTree.listEntries( srcRepository , "" );
 113             System.out.println( );
 114         } catch( SVNException svne ) {
 115             System.err.println( "An error occurred while accessing source repository: " + svne.getErrorMessage( ).getFullMessage( ) );
 116             System.exit( 1 );
 117         }
 118         ...

First, we will try replay() functionality for replicating the source repository. We'll use a simple initialization function that copies revision props from revision 0 of the source repository to the same revision of the target one:

   1     private static void initializeRepository( SVNRepository fromRepos , SVNRepository toRepos ) throws SVNException {
   2         /*
   3          * Initialization means we need to set necessary svn:sync- properties
   4          * on revision 0 of the destination repository. But since our program
   5          * is just an example, we copy only revision properties from the 
   6          * source repository to the destination one.
   7          */
   8         copyRevisionProperties( fromRepos , toRepos , 0 );
   9     }

The routine for copying revision properties:

   1     private static void copyRevisionProperties( SVNRepository fromRepository , SVNRepository toRepository , long revision ) throws SVNException {
   2         Map revProps = fromRepository.getRevisionProperties( revision , null );
   3         for ( Iterator propNames = revProps.keySet( ).iterator( ); propNames.hasNext( ); ) {
   4             String propName = ( String ) propNames.next( );
   5             String propValue = ( String ) revProps.get( propName );
   6             toRepository.setRevisionPropertyValue( revision , propName , propValue );
   7         }
   8     }

And synchronization itself:

   1     private static long synchronizeRepository( SVNRepository fromRepos , SVNRepository toRepos ) throws SVNException {
   2         long lastMergedRevision = 0;
   3         long fromLatestRevision = fromRepos.getLatestRevision( );
   4         long count = 0;
   5         for ( long currentRev = lastMergedRevision + 1 ; currentRev <= fromLatestRevision ; currentRev++ ) {
   6             ISVNEditor commitEditor = toRepos.getCommitEditor( "" , null );
   7             fromRepos.replay( 0 , currentRev , true , commitEditor );
   8             SVNCommitInfo info = commitEditor.closeEdit( );
   9                 
  10             if ( info.getNewRevision( ) != currentRev ) {
  11                 System.err.println( "Commit created rev " + info.getNewRevision( ) + " but should have created " + currentRev );
  12                 System.exit( 1 );
  13             }
  14             System.out.println( "Committed revision " + info.getNewRevision( ) );
  15             copyRevisionProperties( fromRepos , toRepos , currentRev );
  16             count++;
  17         }
  18         return count;
  19     }

If we can't replicate the source repository in case a server does not support replay functionality we would like to use SVNRepositoryReplicator:

   1     private static long replicateRepository( SVNRepository srcRepository , SVNRepository tgtRepository ) throws SVNException {
   2         long latestRevision = srcRepository.getLatestRevision( );
   3         SVNRepositoryReplicator replicator = SVNRepositoryReplicator.newInstance( );
   4         //use this handler to print out progress information on commits
   5         replicator.setReplicationHandler( new ISVNReplicationHandler( ) {
   6 
   7             public void revisionReplicated( SVNRepositoryReplicator source , SVNCommitInfo commitInfo ) throws SVNException {
   8                 System.out.println( "Committed revision " + commitInfo.getNewRevision( ) );
   9             }
  10             
  11             public void revisionReplicating( SVNRepositoryReplicator source , SVNLogEntry logEntry ) throws SVNException {
  12             }
  13             
  14             public void checkCancelled( ) throws SVNCancelException {
  15             }
  16         });
  17         
  18         return replicator.replicateRepository( srcRepository , tgtRepository , 1 , latestRevision );
  19     }

In the main program we call this routines:

   1         ...
   2         
   3         try{
   4             /*
   5              * First let's try the standard replay way.
   6              */
   7             long replicatedRevisions = 0;
   8             try {
   9                 initializeRepository( srcRepository , tgtRepository );
  10                 replicatedRevisions = synchronizeRepository( srcRepository , tgtRepository );
  11             } catch ( SVNException svne ) {
  12                 if ( svne.getErrorMessage( ).getErrorCode( ) != SVNErrorCode.RA_NOT_IMPLEMENTED ) {
  13                     throw svne;
  14                 }
  15 
  16                 //...else the server does not support replay functionality
  17                 tgtRepository = SVNRepositoryFactory.create( tgtURL );
  18                 replicatedRevisions = replicateRepository( srcRepository , tgtRepository );
  19             }
  20             
  21             ...

If the server does not support replay functionality we get SVNErrorCode.RA_NOT_IMPLEMENTED and invoke our replicator. tgtRepository is reinstantiated since it may be locked by its getCommitEditor() method. At the end we print out the number of replicated revisions and the target repository tree:

   1          
   2             ...
   3             
   4             System.out.println( );
   5             System.out.println( "Number of replicated revisions: " + replicatedRevisions );
   6             System.out.println( );
   7             System.out.println( "'" + tgtURL + "' repository tree:" );
   8             System.out.println( );
   9             /*
  10              * Shows the tree of the target repository in the latest revision.
  11              */
  12             DisplayRepositoryTree.listEntries( tgtRepository , "" );
  13         }catch( SVNException svne ) {
  14             System.err.println( "An error occurred while accessing source repository: " + svne.getErrorMessage( ).getFullMessage( ) );
  15             System.exit( 1 );
  16         }
  17     }
  18 }

Running a program:

r1 by 'me' at Wed Apr 26 02:10:14 NOVST 2006
r2 by 'me' at Wed Apr 26 02:10:14 NOVST 2006
r3 by 'me' at Wed Apr 26 02:10:15 NOVST 2006
r4 by 'me' at Wed Apr 26 02:10:15 NOVST 2006
  
The latest source revision: 4
  
'file:///G:/tgtRepository' repository tree:

/dirA (author: 'me'; revision: 4; date: Wed Apr 26 02:10:15 NOVST 2006)
/dirA/dirB (author: 'me'; revision: 4; date: Wed Apr 26 02:10:15 NOVST 2006)
/dirA/dirB/fileB.txt (author: 'me'; revision: 4; date: Wed Apr 26 02:10:15 NOVST 2006)
/dirA/fileA.txt (author: 'me'; revision: 2; date: Wed Apr 26 02:10:14 NOVST 2006)
 
Committed revision 1
Committed revision 2
Committed revision 3
Committed revision 4

Number of replicated revisions: 4

'file:///G:/tgtRepository' repository tree:

/dirA (author: 'me'; revision: 4; date: Wed Apr 26 02:10:15 NOVST 2006)
/dirA/dirB (author: 'me'; revision: 4; date: Wed Apr 26 02:10:15 NOVST 2006)
/dirA/dirB/fileB.txt (author: 'me'; revision: 4; date: Wed Apr 26 02:10:15 NOVST 2006)
/dirA/fileA.txt (author: 'me'; revision: 2; date: Wed Apr 26 02:10:14 NOVST 2006)


Download the example program source code.

Replicating_An_Existing_Repository (last edited 2012-01-03 18:09:33 by ip-109-80-120-205)