package net.oni2.svnaccess; import static java.lang.System.err; import java.io.File; import java.util.Vector; import net.oni2.ProxySettings; import org.tmatesoft.svn.core.SVNDepth; import org.tmatesoft.svn.core.SVNDirEntry; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNURL; import org.tmatesoft.svn.core.auth.BasicAuthenticationManager; import org.tmatesoft.svn.core.auth.SVNAuthentication; 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.ISVNStatusHandler; import org.tmatesoft.svn.core.wc.SVNClientManager; import org.tmatesoft.svn.core.wc.SVNInfo; import org.tmatesoft.svn.core.wc.SVNRevision; import org.tmatesoft.svn.core.wc.SVNStatus; import org.tmatesoft.svn.core.wc.SVNStatusType; import org.tmatesoft.svn.core.wc.SVNWCUtil; /** * SVN handling * * @author Christian Illy */ public class SVN { SVNClientManager svnCManager = null; private void setup() { // For using over http:// and https:// DAVRepositoryFactory.setup(); // For using over svn:// and svn+xxx:// SVNRepositoryFactoryImpl.setup(); // For using over file:/// FSRepositoryFactory.setup(); } private void setProxy(BasicAuthenticationManager authMan) { ProxySettings prox = ProxySettings.getInstance(); if (prox.validate() && prox.isUseProxy()) { authMan.setProxy(prox.getHostOrIp(), prox.getPort(), null, null); } } private BasicAuthenticationManager getAuthManager() { BasicAuthenticationManager auth = new BasicAuthenticationManager( new SVNAuthentication[0]); setProxy(auth); return auth; } private BasicAuthenticationManager getAuthManager(String username, String password) { BasicAuthenticationManager auth = new BasicAuthenticationManager( username, password); setProxy(auth); return auth; } /** * Constructor */ public SVN() { setup(); svnCManager = SVNClientManager.newInstance( SVNWCUtil.createDefaultOptions(true), getAuthManager()); } /** * Constructor with init values * * @param username * Username * @param password * Password */ public SVN(String username, String password) { setup(); svnCManager = SVNClientManager.newInstance( SVNWCUtil.createDefaultOptions(true), getAuthManager(username, password)); } /** * Checkout/update a repository to a local path * * @param reposUrl * Repository URL * @param wcDir * Local path * @param listener * The listener for the status events * @return True if successful * @throws Exception * if missing parameters or something went wrong */ public boolean updateWC(String reposUrl, File wcDir, SVNUpdateListener listener) throws Exception { SVNURL repos = SVNURL.parseURIEncoded(reposUrl); if (wcDir.exists()) { int rev = pathIsWCof(repos, wcDir); if (rev < 0) throw new Exception( "Destination path exists but is not a Working Copy of the SVN"); return update(repos, wcDir, rev, listener); } else { return checkout(repos, wcDir, listener); } } /** * Checks if the SVN contains newer revisions than the local working copy * * @param reposUrl * URL of repository to check for newer revisions * @param wcDir * Local working copy path to compare against * @return -2: No connection to remote repos
* -1: No local working copy yet
* 0: Revisions are equal
* 1: SVN contains newer revisions
* 2: WC has manually deleted files * @throws Exception * If destination is not a WC of the given repository */ public int checkSVN(String reposUrl, File wcDir) throws Exception { SVNURL repos = SVNURL.parseURIEncoded(reposUrl); if (wcDir.exists()) { int localRev = pathIsWCof(repos, wcDir); if (localRev < 0) { if (wcDir.listFiles().length > 0) { throw new Exception( "Destination path exists but is not a Working Copy of the SVN"); } else { wcDir.delete(); return -1; } } int remoteRev = getRemoteHeadRevision(repos); if (remoteRev > localRev) return 1; else { if (remoteRev < 0) { return -2; } else { if (getMissingFiles(wcDir)) return 2; else return 0; } } } else { return -1; } } private boolean getMissingFiles(File wcDir) { try { final Vector files = new Vector(); svnCManager.getStatusClient().doStatus(wcDir, null, SVNDepth.INFINITY, false, false, false, false, new ISVNStatusHandler() { @Override public void handleStatus(SVNStatus status) throws SVNException { SVNStatusType stat = status .getCombinedNodeAndContentsStatus(); if (stat == SVNStatusType.MISSING || stat == SVNStatusType.STATUS_MISSING) { files.add(status.getFile().getPath()); } } }, null); return files.size() > 0; } catch (SVNException e) { e.printStackTrace(); } return false; } private int getRemoteHeadRevision(SVNURL reposUrl) { try { SVNInfo info = svnCManager.getWCClient().doInfo(reposUrl, SVNRevision.HEAD, SVNRevision.HEAD); return (int) info.getRevision().getNumber(); } catch (SVNException e) { e.printStackTrace(); } return -1; } private int pathIsWCof(SVNURL reposUrl, File wcDir) { if (wcDir.exists()) { try { SVNInfo info = svnCManager.getWCClient().doInfo(wcDir, SVNRevision.WORKING); if (info.getURL().equals(reposUrl)) return (int) info.getRevision().getNumber(); } catch (SVNException e) { err.println("Error while getting information of working copy for the location '" + reposUrl + "': " + e.getMessage()); e.printStackTrace(); } } return -1; } private Vector getUpdatedFilesInRepository(SVNURL reposUrl, int fromRev) { Vector list = new Vector(); try { svnCManager.getLogClient().doLog(reposUrl, new String[] { reposUrl.getPath() }, SVNRevision.HEAD, SVNRevision.create(fromRev + 1), SVNRevision.HEAD, true, true, 0, new LogEntryHandler(list, reposUrl.getPath())); } catch (Exception e) { if (!e.getMessage().contains("No such revision ")) { err.println("Error while getting the list of updated files of the location '" + reposUrl + "': " + e.getMessage()); e.printStackTrace(); } } return list; } private boolean update(SVNURL reposUrl, File wcDir, int fromRev, SVNUpdateListener listener) throws Exception { Vector updatedFiles = getUpdatedFilesInRepository(reposUrl, fromRev); svnCManager.getUpdateClient().setEventHandler( new UpdateEventHandler(updatedFiles, listener)); try { svnCManager.getUpdateClient().doUpdate(wcDir, SVNRevision.HEAD, SVNDepth.INFINITY, true, true); return true; } catch (Exception e) { err.println("Error while updating the working copy for the location '" + reposUrl + "': " + e.getMessage()); e.printStackTrace(); } return false; } private Vector getFilesInRepository(SVNURL reposUrl) throws Exception { Vector list = new Vector(); try { svnCManager.getLogClient().doList(reposUrl, SVNRevision.HEAD, SVNRevision.HEAD, false, SVNDepth.INFINITY, SVNDirEntry.DIRENT_ALL, new DirEntryHandler(list)); } catch (Exception e) { err.println("Error while getting the list of files of the location '" + reposUrl + "': " + e.getMessage()); e.printStackTrace(); } return list; } private boolean checkout(SVNURL reposUrl, File wcDir, SVNUpdateListener listener) throws Exception { Vector newFiles = getFilesInRepository(reposUrl); svnCManager.getUpdateClient().setEventHandler( new UpdateEventHandler(newFiles, listener)); boolean result = false; try { wcDir.mkdirs(); svnCManager.getUpdateClient() .doCheckout(reposUrl, wcDir, SVNRevision.HEAD, SVNRevision.HEAD, SVNDepth.INFINITY, true); result = true; } catch (Exception e) { err.println("Error while checking out a working copy for the location '" + reposUrl + "': " + e.getMessage()); e.printStackTrace(); } return result; } }