package fitnesse.revisioncontrol.svn.client;
import fitnesse.revisioncontrol.*;
import fitnesse.revisioncontrol.svn.SVNState;
import org.tmatesoft.svn.core.*;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.wc.*;
import java.io.File;
import java.util.*;
public class SVNClient {
private final SVNClientManager clientManager;
private final Map<SVNStatusType, State> states = new HashMap<SVNStatusType, State>();
private final Map<SVNStatusType, String> errorMsgs = new HashMap<SVNStatusType, String>();
public SVNClient(Properties properties) {
initializeRepositories();
clientManager = initializeClientManager(properties);
initializeSVNStatusTypeToStateMap();
initializeUnhandledSVNStatusTypeToErrorMsgsMap();
}
private void initializeRepositories() {
// for DAV (over http and https)
DAVRepositoryFactory.setup();
// for svn (over svn and svn+ssh)
SVNRepositoryFactoryImpl.setup();
// for local (file)
FSRepositoryFactory.setup();
}
private SVNClientManager initializeClientManager(Properties properties) {
String userName = properties.getProperty("SvnUser");
String password = properties.getProperty("SvnPassword");
if (userName == null || password == null) {
return SVNClientManager.newInstance();
} else {
return SVNClientManager.newInstance(null, userName, password);
}
}
public void doUpdate(File wcPath, NewRevisionResults results) throws SVNException {
SVNUpdateClient client = clientManager.getUpdateClient();
client.setIgnoreExternals(true);
setEventHandler(results, client);
long revision = client.doUpdate(wcPath, SVNRevision.HEAD, SVNDepth.INFINITY, false, true);
results.setNewRevision(revision);
clearEventHandler(client);
}
public void doCommit(File wcPath, String commitMessage, NewRevisionResults results) throws SVNException {
SVNCommitClient client = clientManager.getCommitClient();
setEventHandler(results, client);
SVNCommitInfo svnInfo = client.doCommit(new File[] {wcPath},
false, commitMessage, null, null, false, false, SVNDepth.INFINITY);
long newRevision = svnInfo.getNewRevision();
if (newRevision == -1)
results.setStatus(OperationStatus.NOTHING_TO_DO);
else
results.setNewRevision(newRevision);
clearEventHandler(client);
}
public void doAdd(File wcPath, Results results) throws SVNException {
SVNWCClient client = clientManager.getWCClient();
setEventHandler(results, client);
client.doAdd(wcPath, false, false, false, SVNDepth.INFINITY, false, false);
clearEventHandler(client);
}
public void doDelete(File wcPath, boolean force, Results results) throws SVNException {
SVNWCClient client = clientManager.getWCClient();
setEventHandler(results, client);
client.doDelete(wcPath, force, false);
clearEventHandler(client);
}
public List doLog(File wcPath) throws SVNException {
LogEntryHandler handler = new LogEntryHandler();
clientManager.getLogClient().doLog(new File[]{wcPath},
SVNRevision.BASE, SVNRevision.HEAD,
false, false, 100, handler);
return handler.logEntries;
}
public void doRevert(File wcPath, Results results) throws SVNException {
SVNWCClient client = clientManager.getWCClient();
setEventHandler(results, client);
client.doRevert(new File[]{wcPath}, SVNDepth.INFINITY, null);
clearEventHandler(client);
if (results.getDetails().size() == 0)
results.setStatus(OperationStatus.NOTHING_TO_DO);
}
public void doStatus(File wcPath, StatusResults results) throws SVNException {
SVNStatusClient client = clientManager.getStatusClient();
SVNStatusResultsHandler handler = new SVNStatusResultsHandler(results);
client.doStatus(wcPath, SVNRevision.HEAD, SVNDepth.INFINITY,
true, true, false, false, handler, null);
}
private SVNStatus doLocalStatus(File wcPath) throws SVNException {
return clientManager.getStatusClient().doStatus(wcPath, false);
}
public void doLock(File wcPath, Results results) throws SVNException {
SVNWCClient client = clientManager.getWCClient();
setEventHandler(results, client);
client.doLock(FileUtils.getPathsFromRoot(wcPath, false), false, null);
clearEventHandler(client);
}
public void doUnlock(File wcPath) throws SVNException {
SVNWCClient client = clientManager.getWCClient();
client.doUnlock(FileUtils.getPathsFromRoot(wcPath, false), true);
}
public void doUnlock(File wcPath, Results results) throws SVNException {
SVNWCClient client = clientManager.getWCClient();
setEventHandler(results, client);
client.doUnlock(FileUtils.getPathsFromRoot(wcPath, false), true);
clearEventHandler(client);
}
public void doMove(File src, File dest) throws SVNException {
clientManager.getMoveClient().doMove(src, dest);
}
private static class LogEntryHandler implements ISVNLogEntryHandler {
public List<SVNLogEntry> logEntries = new ArrayList<SVNLogEntry>();
public void handleLogEntry(SVNLogEntry logEntry) {
logEntries.add(logEntry);
}
}
public State getState(File pagePath) {
SVNStatusType status;
try {
SVNStatus svnStatus = doLocalStatus(pagePath);
if (svnStatus == null) {
return SVNState.UNKNOWN;
}
status = svnStatus.getContentsStatus();
} catch (SVNException e) {
return SVNState.UNKNOWN;
}
State state = this.states.get(status);
if (state != null) {
return state;
}
throwExceptionForUnhandledStatuses(status, pagePath);
throw new RevisionControlException(pagePath + " is in an unknown state. Please update the file and try again.");
}
public boolean hasLocalLock(File pagePath) {
try {
SVNStatus svnStatus = doLocalStatus(pagePath);
return svnStatus != null && svnStatus.getLocalLock() != null;
} catch (SVNException e) {
throw new RevisionControlException(pagePath + " is in an unknown state. Can not determine local lock ownership.");
}
}
private void throwExceptionForUnhandledStatuses(final SVNStatusType status, final File fileName) {
String errorMsg = this.errorMsgs.get(status);
if (errorMsg != null) {
throw new RevisionControlException(fileName.getAbsolutePath() + errorMsg);
}
}
private void setEventHandler(Results results, SVNBasicClient client) {
SVNResultsHandler handler = new SVNResultsHandler(results);
client.setEventHandler(handler);
}
private void clearEventHandler(SVNBasicClient client) {
client.setEventHandler(null);
}
private void initializeSVNStatusTypeToStateMap() {
this.states.put(null, SVNState.UNKNOWN);
this.states.put(SVNStatusType.STATUS_UNVERSIONED, SVNState.UNKNOWN);
this.states.put(SVNStatusType.STATUS_NONE, SVNState.UNKNOWN);
this.states.put(SVNStatusType.STATUS_ADDED, SVNState.ADDED);
this.states.put(SVNStatusType.STATUS_DELETED, SVNState.DELETED);
this.states.put(SVNStatusType.STATUS_NORMAL, SVNState.VERSIONED);
this.states.put(SVNStatusType.STATUS_MODIFIED, SVNState.VERSIONED);
this.states.put(SVNStatusType.STATUS_REPLACED, SVNState.VERSIONED);
this.states.put(SVNStatusType.STATUS_IGNORED, SVNState.UNKNOWN);
this.states.put(SVNStatusType.MERGED, SVNState.VERSIONED);
}
private void initializeUnhandledSVNStatusTypeToErrorMsgsMap() {
this.errorMsgs.put(SVNStatusType.STATUS_CONFLICTED, " has conflicts");
this.errorMsgs.put(SVNStatusType.STATUS_MISSING, " is missing from the working copy");
this.errorMsgs.put(SVNStatusType.STATUS_IGNORED, " is marked to be Ignored by SVN. Cannot perform SVN operations on ignored files");
this.errorMsgs.put(SVNStatusType.STATUS_EXTERNAL, " is an SVN External File. Cannot perform local SVN operatiosn on external files");
this.errorMsgs.put(SVNStatusType.STATUS_INCOMPLETE, " is marked as incomplete by SVN. Please update the file and try again");
this.errorMsgs.put(SVNStatusType.STATUS_OBSTRUCTED, " is marked as obstructed by SVN. Please clean the working copy and try again");
}
}