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