| 1 | package net.oni2.svnaccess; | 
 
 
 
 
 | 2 |  | 
 
 
 
 
 | 3 | import static java.lang.System.err; | 
 
 
 
 
 | 4 |  | 
 
 
 
 
 | 5 | import java.io.File; | 
 
 
 
 
 | 6 | import java.util.Vector; | 
 
 
 
 
 | 7 |  | 
 
 
 
 
 | 8 | import org.tmatesoft.svn.core.SVNDepth; | 
 
 
 
 
 | 9 | import org.tmatesoft.svn.core.SVNDirEntry; | 
 
 
 
 
 | 10 | import org.tmatesoft.svn.core.SVNException; | 
 
 
 
 
 | 11 | import org.tmatesoft.svn.core.SVNURL; | 
 
 
 
 
 | 12 | import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory; | 
 
 
 
 
 | 13 | import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory; | 
 
 
 
 
 | 14 | import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl; | 
 
 
 
 
 | 15 | import org.tmatesoft.svn.core.wc.ISVNStatusHandler; | 
 
 
 
 
 | 16 | import org.tmatesoft.svn.core.wc.SVNClientManager; | 
 
 
 
 
 | 17 | import org.tmatesoft.svn.core.wc.SVNInfo; | 
 
 
 
 
 | 18 | import org.tmatesoft.svn.core.wc.SVNRevision; | 
 
 
 
 
 | 19 | import org.tmatesoft.svn.core.wc.SVNStatus; | 
 
 
 
 
 | 20 | import org.tmatesoft.svn.core.wc.SVNStatusType; | 
 
 
 
 
 | 21 | import org.tmatesoft.svn.core.wc.SVNWCUtil; | 
 
 
 
 
 | 22 |  | 
 
 
 
 
 | 23 | /** | 
 
 
 
 
 | 24 | * SVN handling | 
 
 
 
 
 | 25 | * | 
 
 
 
 
 | 26 | * @author Christian Illy | 
 
 
 
 
 | 27 | */ | 
 
 
 
 
 | 28 | public class SVN { | 
 
 
 
 
 | 29 |  | 
 
 
 
 
 | 30 | SVNClientManager svnCManager = null; | 
 
 
 
 
 | 31 |  | 
 
 
 
 
 | 32 | /** | 
 
 
 
 
 | 33 | * Constructor | 
 
 
 
 
 | 34 | */ | 
 
 
 
 
 | 35 | public SVN() { | 
 
 
 
 
 | 36 | // For using over http:// and https:// | 
 
 
 
 
 | 37 | DAVRepositoryFactory.setup(); | 
 
 
 
 
 | 38 | // For using over svn:// and svn+xxx:// | 
 
 
 
 
 | 39 | SVNRepositoryFactoryImpl.setup(); | 
 
 
 
 
 | 40 | // For using over file:/// | 
 
 
 
 
 | 41 | FSRepositoryFactory.setup(); | 
 
 
 
 
 | 42 |  | 
 
 
 
 
 | 43 | svnCManager = SVNClientManager.newInstance(SVNWCUtil | 
 
 
 
 
 | 44 | .createDefaultOptions(true)); | 
 
 
 
 
 | 45 | } | 
 
 
 
 
 | 46 |  | 
 
 
 
 
 | 47 | /** | 
 
 
 
 
 | 48 | * Constructor with init values | 
 
 
 
 
 | 49 | * | 
 
 
 
 
 | 50 | * @param username | 
 
 
 
 
 | 51 | *            Username | 
 
 
 
 
 | 52 | * @param password | 
 
 
 
 
 | 53 | *            Password | 
 
 
 
 
 | 54 | */ | 
 
 
 
 
 | 55 | public SVN(String username, String password) { | 
 
 
 
 
 | 56 | // For using over http:// and https:// | 
 
 
 
 
 | 57 | DAVRepositoryFactory.setup(); | 
 
 
 
 
 | 58 | // For using over svn:// and svn+xxx:// | 
 
 
 
 
 | 59 | SVNRepositoryFactoryImpl.setup(); | 
 
 
 
 
 | 60 | // For using over file:/// | 
 
 
 
 
 | 61 | FSRepositoryFactory.setup(); | 
 
 
 
 
 | 62 |  | 
 
 
 
 
 | 63 | svnCManager = SVNClientManager.newInstance( | 
 
 
 
 
 | 64 | SVNWCUtil.createDefaultOptions(true), username, password); | 
 
 
 
 
 | 65 | } | 
 
 
 
 
 | 66 |  | 
 
 
 
 
 | 67 | /** | 
 
 
 
 
 | 68 | * Checkout/update a repository to a local path | 
 
 
 
 
 | 69 | * | 
 
 
 
 
 | 70 | * @param reposUrl | 
 
 
 
 
 | 71 | *            Repository URL | 
 
 
 
 
 | 72 | * @param wcDir | 
 
 
 
 
 | 73 | *            Local path | 
 
 
 
 
 | 74 | * @param listener | 
 
 
 
 
 | 75 | *            The listener for the status events | 
 
 
 
 
 | 76 | * @return True if successful | 
 
 
 
 
 | 77 | * @throws Exception | 
 
 
 
 
 | 78 | *             if missing parameters or something went wrong | 
 
 
 
 
 | 79 | */ | 
 
 
 
 
 | 80 | public boolean updateWC(String reposUrl, File wcDir, | 
 
 
 
 
 | 81 | SVNUpdateListener listener) throws Exception { | 
 
 
 
 
 | 82 | SVNURL repos = SVNURL.parseURIEncoded(reposUrl); | 
 
 
 
 
 | 83 |  | 
 
 
 
 
 | 84 | if (wcDir.exists()) { | 
 
 
 
 
 | 85 | int rev = pathIsWCof(repos, wcDir); | 
 
 
 
 
 | 86 | if (rev < 0) | 
 
 
 
 
 | 87 | throw new Exception( | 
 
 
 
 
 | 88 | "Destination path exists but is not a Working Copy of the SVN"); | 
 
 
 
 
 | 89 | return update(repos, wcDir, rev, listener); | 
 
 
 
 
 | 90 | } else { | 
 
 
 
 
 | 91 | return checkout(repos, wcDir, listener); | 
 
 
 
 
 | 92 | } | 
 
 
 
 
 | 93 | } | 
 
 
 
 
 | 94 |  | 
 
 
 
 
 | 95 | /** | 
 
 
 
 
 | 96 | * Checks if the SVN contains newer revisions than the local working copy | 
 
 
 
 
 | 97 | * | 
 
 
 
 
 | 98 | * @param reposUrl | 
 
 
 
 
 | 99 | *            URL of repository to check for newer revisions | 
 
 
 
 
 | 100 | * @param wcDir | 
 
 
 
 
 | 101 | *            Local working copy path to compare against | 
 
 
 
 
 | 102 | * @return -1: No local working copy yet<br> | 
 
 
 
 
 | 103 | *         0: Revisions are equal<br> | 
 
 
 
 
 | 104 | *         1: SVN contains newer revisions<br> | 
 
 
 
 
 | 105 | *         2: WC has manually deleted files | 
 
 
 
 
 | 106 | * @throws Exception | 
 
 
 
 
 | 107 | *             If destination is not a WC of the given repository | 
 
 
 
 
 | 108 | */ | 
 
 
 
 
 | 109 | public int checkSVN(String reposUrl, File wcDir) throws Exception { | 
 
 
 
 
 | 110 | SVNURL repos = SVNURL.parseURIEncoded(reposUrl); | 
 
 
 
 
 | 111 |  | 
 
 
 
 
 | 112 | if (wcDir.exists()) { | 
 
 
 
 
 | 113 | int localRev = pathIsWCof(repos, wcDir); | 
 
 
 
 
 | 114 | if (localRev < 0) | 
 
 
 
 
 | 115 | throw new Exception( | 
 
 
 
 
 | 116 | "Destination path exists but is not a Working Copy of the SVN"); | 
 
 
 
 
 | 117 | int remoteRev = getRemoteHeadRevision(repos); | 
 
 
 
 
 | 118 | if (remoteRev > localRev) | 
 
 
 
 
 | 119 | return 1; | 
 
 
 
 
 | 120 | else { | 
 
 
 
 
 | 121 | if (getMissingFiles(wcDir)) | 
 
 
 
 
 | 122 | return 2; | 
 
 
 
 
 | 123 | else | 
 
 
 
 
 | 124 | return 0; | 
 
 
 
 
 | 125 | } | 
 
 
 
 
 | 126 | } else { | 
 
 
 
 
 | 127 | return -1; | 
 
 
 
 
 | 128 | } | 
 
 
 
 
 | 129 | } | 
 
 
 
 
 | 130 |  | 
 
 
 
 
 | 131 | private boolean getMissingFiles(File wcDir) { | 
 
 
 
 
 | 132 | try { | 
 
 
 
 
 | 133 | final Vector<String> files = new Vector<String>(); | 
 
 
 
 
 | 134 | svnCManager.getStatusClient().doStatus(wcDir, null, | 
 
 
 
 
 | 135 | SVNDepth.INFINITY, false, false, false, false, | 
 
 
 
 
 | 136 | new ISVNStatusHandler() { | 
 
 
 
 
 | 137 | @Override | 
 
 
 
 
 | 138 | public void handleStatus(SVNStatus status) | 
 
 
 
 
 | 139 | throws SVNException { | 
 
 
 
 
 | 140 | SVNStatusType stat = status | 
 
 
 
 
 | 141 | .getCombinedNodeAndContentsStatus(); | 
 
 
 
 
 | 142 | if (stat == SVNStatusType.MISSING | 
 
 
 
 
 | 143 | || stat == SVNStatusType.STATUS_MISSING) { | 
 
 
 
 
 | 144 | files.add(status.getFile().getPath()); | 
 
 
 
 
 | 145 | } | 
 
 
 
 
 | 146 | } | 
 
 
 
 
 | 147 | }, null); | 
 
 
 
 
 | 148 | return files.size() > 0; | 
 
 
 
 
 | 149 | } catch (SVNException e) { | 
 
 
 
 
 | 150 | e.printStackTrace(); | 
 
 
 
 
 | 151 | } | 
 
 
 
 
 | 152 | return false; | 
 
 
 
 
 | 153 | } | 
 
 
 
 
 | 154 |  | 
 
 
 
 
 | 155 | private int getRemoteHeadRevision(SVNURL reposUrl) { | 
 
 
 
 
 | 156 | try { | 
 
 
 
 
 | 157 | SVNInfo info = svnCManager.getWCClient().doInfo(reposUrl, | 
 
 
 
 
 | 158 | SVNRevision.HEAD, SVNRevision.HEAD); | 
 
 
 
 
 | 159 | return (int) info.getRevision().getNumber(); | 
 
 
 
 
 | 160 | } catch (SVNException e) { | 
 
 
 
 
 | 161 | e.printStackTrace(); | 
 
 
 
 
 | 162 | } | 
 
 
 
 
 | 163 | return -1; | 
 
 
 
 
 | 164 | } | 
 
 
 
 
 | 165 |  | 
 
 
 
 
 | 166 | private int pathIsWCof(SVNURL reposUrl, File wcDir) { | 
 
 
 
 
 | 167 | if (wcDir.exists()) { | 
 
 
 
 
 | 168 | try { | 
 
 
 
 
 | 169 | SVNInfo info = svnCManager.getWCClient().doInfo(wcDir, | 
 
 
 
 
 | 170 | SVNRevision.WORKING); | 
 
 
 
 
 | 171 |  | 
 
 
 
 
 | 172 | if (info.getURL().equals(reposUrl)) | 
 
 
 
 
 | 173 | return (int) info.getRevision().getNumber(); | 
 
 
 
 
 | 174 | } catch (SVNException e) { | 
 
 
 
 
 | 175 | err.println("Error while getting information of working copy for the location '" | 
 
 
 
 
 | 176 | + reposUrl + "': " + e.getMessage()); | 
 
 
 
 
 | 177 | } | 
 
 
 
 
 | 178 | } | 
 
 
 
 
 | 179 | return -1; | 
 
 
 
 
 | 180 | } | 
 
 
 
 
 | 181 |  | 
 
 
 
 
 | 182 | private Vector<String> getUpdatedFilesInRepository(SVNURL reposUrl, | 
 
 
 
 
 | 183 | int fromRev) { | 
 
 
 
 
 | 184 | Vector<String> list = new Vector<String>(); | 
 
 
 
 
 | 185 | try { | 
 
 
 
 
 | 186 | svnCManager.getLogClient().doLog(reposUrl, | 
 
 
 
 
 | 187 | new String[] { reposUrl.getPath() }, SVNRevision.HEAD, | 
 
 
 
 
 | 188 | SVNRevision.create(fromRev + 1), SVNRevision.HEAD, true, | 
 
 
 
 
 | 189 | true, 0, new LogEntryHandler(list, reposUrl.getPath())); | 
 
 
 
 
 | 190 | } catch (Exception e) { | 
 
 
 
 
 | 191 | if (!e.getMessage().contains("No such revision ")) { | 
 
 
 
 
 | 192 | err.println("Error while getting the list of updated files of the location '" | 
 
 
 
 
 | 193 | + reposUrl + "': " + e.getMessage()); | 
 
 
 
 
 | 194 | e.printStackTrace(); | 
 
 
 
 
 | 195 | } | 
 
 
 
 
 | 196 | } | 
 
 
 
 
 | 197 |  | 
 
 
 
 
 | 198 | return list; | 
 
 
 
 
 | 199 | } | 
 
 
 
 
 | 200 |  | 
 
 
 
 
 | 201 | private boolean update(SVNURL reposUrl, File wcDir, int fromRev, | 
 
 
 
 
 | 202 | SVNUpdateListener listener) throws Exception { | 
 
 
 
 
 | 203 | Vector<String> updatedFiles = getUpdatedFilesInRepository(reposUrl, | 
 
 
 
 
 | 204 | fromRev); | 
 
 
 
 
 | 205 |  | 
 
 
 
 
 | 206 | svnCManager.getUpdateClient().setEventHandler( | 
 
 
 
 
 | 207 | new UpdateEventHandler(updatedFiles, listener)); | 
 
 
 
 
 | 208 |  | 
 
 
 
 
 | 209 | try { | 
 
 
 
 
 | 210 | svnCManager.getUpdateClient().doUpdate(wcDir, SVNRevision.HEAD, | 
 
 
 
 
 | 211 | SVNDepth.INFINITY, true, true); | 
 
 
 
 
 | 212 | return true; | 
 
 
 
 
 | 213 | } catch (Exception e) { | 
 
 
 
 
 | 214 | err.println("Error while updating the working copy for the location '" | 
 
 
 
 
 | 215 | + reposUrl + "': " + e.getMessage()); | 
 
 
 
 
 | 216 | } | 
 
 
 
 
 | 217 | return false; | 
 
 
 
 
 | 218 | } | 
 
 
 
 
 | 219 |  | 
 
 
 
 
 | 220 | private Vector<String> getFilesInRepository(SVNURL reposUrl) | 
 
 
 
 
 | 221 | throws Exception { | 
 
 
 
 
 | 222 | Vector<String> list = new Vector<String>(); | 
 
 
 
 
 | 223 | try { | 
 
 
 
 
 | 224 | svnCManager.getLogClient().doList(reposUrl, SVNRevision.HEAD, | 
 
 
 
 
 | 225 | SVNRevision.HEAD, false, SVNDepth.INFINITY, | 
 
 
 
 
 | 226 | SVNDirEntry.DIRENT_ALL, new DirEntryHandler(list)); | 
 
 
 
 
 | 227 | } catch (Exception e) { | 
 
 
 
 
 | 228 | err.println("Error while getting the list of files of the location '" | 
 
 
 
 
 | 229 | + reposUrl + "': " + e.getMessage()); | 
 
 
 
 
 | 230 | } | 
 
 
 
 
 | 231 | return list; | 
 
 
 
 
 | 232 | } | 
 
 
 
 
 | 233 |  | 
 
 
 
 
 | 234 | private boolean checkout(SVNURL reposUrl, File wcDir, | 
 
 
 
 
 | 235 | SVNUpdateListener listener) throws Exception { | 
 
 
 
 
 | 236 | Vector<String> newFiles = getFilesInRepository(reposUrl); | 
 
 
 
 
 | 237 | svnCManager.getUpdateClient().setEventHandler( | 
 
 
 
 
 | 238 | new UpdateEventHandler(newFiles, listener)); | 
 
 
 
 
 | 239 |  | 
 
 
 
 
 | 240 | boolean result = false; | 
 
 
 
 
 | 241 | try { | 
 
 
 
 
 | 242 | wcDir.mkdirs(); | 
 
 
 
 
 | 243 | svnCManager.getUpdateClient() | 
 
 
 
 
 | 244 | .doCheckout(reposUrl, wcDir, SVNRevision.HEAD, | 
 
 
 
 
 | 245 | SVNRevision.HEAD, SVNDepth.INFINITY, true); | 
 
 
 
 
 | 246 | result = true; | 
 
 
 
 
 | 247 | } catch (Exception e) { | 
 
 
 
 
 | 248 | err.println("Error while checking out a working copy for the location '" | 
 
 
 
 
 | 249 | + reposUrl + "': " + e.getMessage()); | 
 
 
 
 
 | 250 | } | 
 
 
 
 
 | 251 | return result; | 
 
 
 
 
 | 252 | } | 
 
 
 
 
 | 253 | } |