Search code examples
javasvnsvnkit

Get previous modified revision of a file using svnkit


I am using SVN kit to gather some metrics from SVN repositories. I am stuck with this simple problem and am unable to get through it.

I have an SVNRepository object that give me paths of all files in the repository and their different revisions. I want to set previous revision value for each of the revision. How can I do that without checking out that file? Or rather what is the best way to do it so as to have best performance from my code?

It should also consider the copy/paste and move activity when allotting the previous revision.


Solution

  • Following technique worked for me.

    //This is where I query SVN server
    if (entryPath.getType() != SVNLogEntryPath.TYPE_ADDED) {
        LogEntryPreviousRevFinder handler = new LogEntryPreviousRevFinder(workingFileName.substring(interestingPath.length()), thisRevision);
    
        //Start checking for previous modified revision for this file in the previous 3 revision.
        //If not found try for previous 5 and then 7. If not found till then, put in a warning and continue.
        //This is necessary because in SVN a branch operation is performed at the folder level and not file 
        //hence we need to go further back and find out the revision than was last modified.
        for (int i = 3; i <= 7; i+=2) {
            repository.log(new String[] {workingFileName}, thisRevision, 0l, true, false, i, handler);
            if (handler.isSuccess()) {
                prevPath = handler.getPreviousPath();
                prevRevision = handler.getPreviousRevision();
                break;
            } else {
                continue;
            }
        }
    
        if (!handler.isSuccess()) {
            log.warn("Failed to find previous revision for file: " + workingFileName 
                    + " Will contine considering this one as added in this revision");
        }
    } else {
        //Files with SVNLogEntryPath.TYPE_ADDED are either added in this revision
        //or are copied or renamed from an existing file. If later, we need to identify the Copy from path
        //as that will be the file which will be used for calculating relative metrics and later Flux values
        if (entryPath.getCopyPath() != null && entryPath.getCopyPath().trim().length() > 0) {
            prevPath = entryPath.getCopyPath();
            prevRevision = entryPath.getCopyRevision();
        } else {
            log.debug("File: " + workingFileName + " added in this revision");
        }
    }
    

    ISVNLogEntryHandler implementation:

    //ISVNLogEntryHandler implementation for identifying previous revision
    private class LogEntryPreviousRevFinder implements ISVNLogEntryHandler {
        private String interestingFile;
        private String previousPath;
        private long thisRevision;
        private long previousRevision;
        private boolean isSuccess;
    
        public LogEntryPreviousRevFinder(String interestingFile, long revision) {
            this.interestingFile = interestingFile;
            this.thisRevision = revision;
            isSuccess = false;
        }
    
        @Override
        public void handleLogEntry(SVNLogEntry logEntry) throws SVNException {
            if (isSuccess)
                return;
    
            if (thisRevision == logEntry.getRevision())
                return;
    
            Set changedPathsSet = logEntry.getChangedPaths().keySet();
            for (Iterator changedPaths = changedPathsSet.iterator(); changedPaths.hasNext();) {
                SVNLogEntryPath entryPath = (SVNLogEntryPath) logEntry.getChangedPaths().get(changedPaths.next());
                String workingFileName = entryPath.getPath();
    
                if (workingFileName.endsWith(interestingFile)) {
                    previousRevision = logEntry.getRevision();
                    previousPath = workingFileName;
                    isSuccess = true;
                }
            }
        }
    
        public long getPreviousRevision() {
            return previousRevision;
        }
        public String getPreviousPath() {
            return previousPath;
        }
        public boolean isSuccess() {
            return isSuccess;
        }
    }
    

    I wonder if there is a better and more efficient way to do this.