Friday 24 May 2013

SVN integration using SVNKit

What is SVNKit?

SVNKit is an open source java based library for working with / integrating with SVN (Subversion control system). Click here to get more details on SVNKit.
I have compiled below some simple sample code fragments that show you how to get started with SVNKit to connect with svn and perform different kind of operations like check-in, check-out, export using the right SVNKit APIs.

Where to download it from?

SVNKit can be downloaded from here.
To do any operation with a SVNKit, first thing we need to do is obtain a SVNClientManager.

Code Samples on using SVNKit 

Obtaining a SVNClientManager

Following code fragment shows how to obtain a SVNClientManager:

public SVNClientManager getSVNClientManager () throws IOException{
             SVNURL url = SVNURL
                  .parseURIDecoded("<path to the base svn repository>");                    
             SVNRepository repository = SVNRepositoryFactory.create(url, null);
             ISVNOptions myOptions = SVNWCUtil.createDefaultOptions(true);
            //provide svn username and password

            //username = name used to connect to svn
            //password = password used to connect to svn
            ISVNAuthenticationManager myAuthManager = SVNWCUtil
                .createDefaultAuthenticationManager("<username>", "<password>");
           repository.setAuthenticationManager(myAuthManager);
        //clientManager will be used to get different kind of svn clients instances to do different activities

       //like update, commit, view diff etc.
        SVNClientManager clientManager = SVNClientManager.newInstance(
                myOptions, myAuthManager);

}

Once SVNClientManager is obtained, there are different kind of 'svn client' classes that it can provide to do different kind of svn operations like check-in, check-out, add, export resources (files and folders). Below is provided sample code example for each kind of svn operations that we might be interested to perform:


Checking in a completely new file or folder into SVN

 public void commitToSvn(SVNClientManager clientManager)
            throws SVNException {
        SVNCommitClient commitClient = clientManager.getCommitClient();
        File fileToCheckin = new File("LocalDir/SampleFileFolder/SampleFile1");
        boolean recursive = true;       
       SVNCommitInfo importInfo = commitClient
                .doImport
(
                        fileToCheckin ,
                        SVNURL.parseURIDecoded("<path at which we want to check-in the file>"),
                        "testing svn kit integration", recursive);
        System.out.println(importInfo.getNewRevision());
    }
As shown by the highlighted code above, the svn client used to check-in completely new resources is 'SVNCommitClient' and the API that it used for this purpose is 'doImport(File fileToCheckin, SVNURL svnUrlAtWhichToCheckInFile, String comment, boolean recursive)'. If we want to check-in a folder and all its sub-folders and files recursively, then the last argument (boolean recursive) needs to be set to true.

Checking out a resource that exists in svn, modifying it and check-in back to svn

     public void checkOutChangeAndCheckIn(SVNClientManager clientManager) throws IOException, SVNException {
        SVNUpdateClient updateClient = clientManager.getUpdateClient();
        updateClient.setIgnoreExternals(false);
       //we are checking out a resource 'SampleFileFolder' which is having a file 'SampleFile1'
       //and putting it under 'LocalDir' in our local machine.
        SVNURL url = SVNURL
                .parseURIDecoded("<path to checkout resource from>");
        File destPath = new File("LocalDir");
        SVNRevision revision = SVNRevision.create(<revision number which we obtained when we checked in the file for the first time in the above section of code >);
        boolean isRecursive = true;
        long doCheckout = updateClient.doCheckout(url, destPath, revision,
                revision, isRecursive);
        System.out.println(doCheckout);

        
         //re-write the content of the checked-out file
        File file = new File("LocalDir/SampleFileFolder/SampleFile1");
        FileOutputStream fos = new FileOutputStream(file, false);
        StringBuffer newContent = new StringBuffer();
        newContent.append("This is new content for new version of file");
        fos.write(newContent.toString().getBytes());
        fos.flush();
        fos.close();
        
        //check-in the file folder back into svn
        SVNCommitClient commitClient = clientManager.getCommitClient();
        File[] paths = { new File("LocalDir/SampleFileFolder/SampleFile1") };
        //this should be set to false as it will keep the file locked after checkin
        boolean keepLocks = false;
        String commitMessage = "new version of sample file1 commited";
        boolean force = true;
        boolean recursive = true;
        SVNCommitInfo commitInfo = commitClient.doCommit(paths, keepLocks,
                commitMessage, force, recursive);
        System.out.println(commitInfo.getNewRevision());
    }

As seen in the above code sample, we checkout the file which we previously had checked-in into svn using SVNCommitClient.doImport API. The API that we use to check-out the folder is SVNUpdateClient.doCheckout. Then we make some changes in this checked-out file and commit it back to svn using the API SVNCommitClient.doCommit
PS: SVNCommitClient.doCommit is used to commit new set of changes to an existing file / folder in svn , if the file or folder doesn't already exist in the svn and we try to use this API, it will give error.
Similarly  SVNCommitClient.doImport is used for new files, if the file already exists in svn, then this API will throw exception complaining that the file already exists in svn.


Exporting a file from svn

    public void exportFromSvn(SVNClientManager clientManager) throws SVNException {
        SVNUpdateClient updateClient = clientManager.getUpdateClient();
        SVNURL url = SVNURL.parseURIDecoded("<svn url to export from>");
        //destination path
        File dstPath = new File("LocalDirNew");
        //the revision number which should be looked upon for the file path
        SVNRevision pegRevision = SVNRevision.create(<right svn revision number>);
        //the revision number which is required to be exported.
        SVNRevision revision = SVNRevision.create(
<right svn revision number>);
        //if there is any special character for end of line (in the file) then it is required. For our use case, //it can be null, assuming there are no special characters. In this case the OS specific EoF style will //be assumed
        String eolStyle = null;
        //this would force the operation
        boolean force = true;
        //Till what extent under a directory, export is required, is determined by depth. INFINITY means the whole subtree of that directory will be exported
        SVNDepth recursive = SVNDepth.INFINITY;
        updateClient.doExport(url, dstPath, pegRevision, revision, eolStyle, force, recursive );
    }

SVNUpdateClient.doExport is used to export a svn resource to a particular location.
Difference between export and check-out : when a resource is checked-out from svn then the svn properties (Stored in .svn files) are also checked-out into the local machine, but when a resource is exported using the doExport API , svn info is not exported along with the resources.

Finding diff between resources using SVNKit:

     private static void viewDiff(SVNClientManager clientManager)
            throws SVNException, IOException {      
        SVNDiffClient diffClient = clientManager.getDiffClient();
        // diff between two versions in svn:
        File svnDiffFile = new File("LocalDir/SvnDiffFile");
        svnDiffFile.createNewFile();
        SVNURL url1 = SVNURL
                .parseURIDecoded("<svn-file-url-for-file-whose-revisions-are-to-be-compared>");
        SVNURL url2 = SVNURL
                .parseURIDecoded("
<svn-file-url-for-file-whose-revisions-are-to-be-compared>");
        SVNRevision rN = SVNRevision.create(<revision-no-1>);
        SVNRevision rM = SVNRevision.create(<revision-no-2>);
        boolean recursive = true;
        //i didn't see the meaning of this parameter, setting it to false worked fine for me.
        boolean useAncestry = false;
        OutputStream result = new FileOutputStream(svnDiffFile);
        diffClient.doDiff(url1, rN, url2, rM, recursive, useAncestry, result);

        // diff between a file and a svn revision number
        File path1 = new File("LocalDir/SampleFile");
        rN = SVNRevision.WORKING;
        rM = SVNRevision.create(
<revision-no-1>);
        File svnToWorkingDiffFile = new File("LocalDir/SvnToWorkingDiff");
        svnToWorkingDiffFile.createNewFile();
        OutputStream result1 = new FileOutputStream(svnToWorkingDiffFile);
        diffClient.doDiff(path1, rN, url2, rM, recursive, useAncestry, result1);
}

API doc for different svn-clients and their APIs are available in the svn-kit-api-doc (javadoc) . Detailed architecture and documentation is present at the documentation section in the svnkit website.

3 comments:

  1. Great write up! These examples/resources have helped me tremendously. Many thanks.

    ReplyDelete
    Replies
    1. Glad that it helped you. You are most welcome!

      Delete
    2. Glad that it helped you. You are most welcome!

      Delete