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()) { |
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 -1: No local working copy yet<br> |
129 |
* 0: Revisions are equal<br> |
130 |
* 1: SVN contains newer revisions<br> |
131 |
* 2: WC has manually deleted files |
132 |
* @throws Exception |
133 |
* If destination is not a WC of the given repository |
134 |
*/ |
135 |
public int checkSVN(String reposUrl, File wcDir) throws Exception { |
136 |
SVNURL repos = SVNURL.parseURIEncoded(reposUrl); |
137 |
|
138 |
if (wcDir.exists()) { |
139 |
int localRev = pathIsWCof(repos, wcDir); |
140 |
if (localRev < 0) |
141 |
throw new Exception( |
142 |
"Destination path exists but is not a Working Copy of the SVN"); |
143 |
int remoteRev = getRemoteHeadRevision(repos); |
144 |
if (remoteRev > localRev) |
145 |
return 1; |
146 |
else { |
147 |
if (getMissingFiles(wcDir)) |
148 |
return 2; |
149 |
else |
150 |
return 0; |
151 |
} |
152 |
} else { |
153 |
return -1; |
154 |
} |
155 |
} |
156 |
|
157 |
private boolean getMissingFiles(File wcDir) { |
158 |
try { |
159 |
final Vector<String> files = new Vector<String>(); |
160 |
svnCManager.getStatusClient().doStatus(wcDir, null, |
161 |
SVNDepth.INFINITY, false, false, false, false, |
162 |
new ISVNStatusHandler() { |
163 |
@Override |
164 |
public void handleStatus(SVNStatus status) |
165 |
throws SVNException { |
166 |
SVNStatusType stat = status |
167 |
.getCombinedNodeAndContentsStatus(); |
168 |
if (stat == SVNStatusType.MISSING |
169 |
|| stat == SVNStatusType.STATUS_MISSING) { |
170 |
files.add(status.getFile().getPath()); |
171 |
} |
172 |
} |
173 |
}, null); |
174 |
return files.size() > 0; |
175 |
} catch (SVNException e) { |
176 |
e.printStackTrace(); |
177 |
} |
178 |
return false; |
179 |
} |
180 |
|
181 |
private int getRemoteHeadRevision(SVNURL reposUrl) { |
182 |
try { |
183 |
SVNInfo info = svnCManager.getWCClient().doInfo(reposUrl, |
184 |
SVNRevision.HEAD, SVNRevision.HEAD); |
185 |
return (int) info.getRevision().getNumber(); |
186 |
} catch (SVNException e) { |
187 |
e.printStackTrace(); |
188 |
} |
189 |
return -1; |
190 |
} |
191 |
|
192 |
private int pathIsWCof(SVNURL reposUrl, File wcDir) { |
193 |
if (wcDir.exists()) { |
194 |
try { |
195 |
SVNInfo info = svnCManager.getWCClient().doInfo(wcDir, |
196 |
SVNRevision.WORKING); |
197 |
|
198 |
if (info.getURL().equals(reposUrl)) |
199 |
return (int) info.getRevision().getNumber(); |
200 |
} catch (SVNException e) { |
201 |
err.println("Error while getting information of working copy for the location '" |
202 |
+ reposUrl + "': " + e.getMessage()); |
203 |
} |
204 |
} |
205 |
return -1; |
206 |
} |
207 |
|
208 |
private Vector<String> getUpdatedFilesInRepository(SVNURL reposUrl, |
209 |
int fromRev) { |
210 |
Vector<String> list = new Vector<String>(); |
211 |
try { |
212 |
svnCManager.getLogClient().doLog(reposUrl, |
213 |
new String[] { reposUrl.getPath() }, SVNRevision.HEAD, |
214 |
SVNRevision.create(fromRev + 1), SVNRevision.HEAD, true, |
215 |
true, 0, new LogEntryHandler(list, reposUrl.getPath())); |
216 |
} catch (Exception e) { |
217 |
if (!e.getMessage().contains("No such revision ")) { |
218 |
err.println("Error while getting the list of updated files of the location '" |
219 |
+ reposUrl + "': " + e.getMessage()); |
220 |
e.printStackTrace(); |
221 |
} |
222 |
} |
223 |
|
224 |
return list; |
225 |
} |
226 |
|
227 |
private boolean update(SVNURL reposUrl, File wcDir, int fromRev, |
228 |
SVNUpdateListener listener) throws Exception { |
229 |
Vector<String> updatedFiles = getUpdatedFilesInRepository(reposUrl, |
230 |
fromRev); |
231 |
|
232 |
svnCManager.getUpdateClient().setEventHandler( |
233 |
new UpdateEventHandler(updatedFiles, listener)); |
234 |
|
235 |
try { |
236 |
svnCManager.getUpdateClient().doUpdate(wcDir, SVNRevision.HEAD, |
237 |
SVNDepth.INFINITY, true, true); |
238 |
return true; |
239 |
} catch (Exception e) { |
240 |
err.println("Error while updating the working copy for the location '" |
241 |
+ reposUrl + "': " + e.getMessage()); |
242 |
} |
243 |
return false; |
244 |
} |
245 |
|
246 |
private Vector<String> getFilesInRepository(SVNURL reposUrl) |
247 |
throws Exception { |
248 |
Vector<String> list = new Vector<String>(); |
249 |
try { |
250 |
svnCManager.getLogClient().doList(reposUrl, SVNRevision.HEAD, |
251 |
SVNRevision.HEAD, false, SVNDepth.INFINITY, |
252 |
SVNDirEntry.DIRENT_ALL, new DirEntryHandler(list)); |
253 |
} catch (Exception e) { |
254 |
err.println("Error while getting the list of files of the location '" |
255 |
+ reposUrl + "': " + e.getMessage()); |
256 |
} |
257 |
return list; |
258 |
} |
259 |
|
260 |
private boolean checkout(SVNURL reposUrl, File wcDir, |
261 |
SVNUpdateListener listener) throws Exception { |
262 |
Vector<String> newFiles = getFilesInRepository(reposUrl); |
263 |
svnCManager.getUpdateClient().setEventHandler( |
264 |
new UpdateEventHandler(newFiles, listener)); |
265 |
|
266 |
boolean result = false; |
267 |
try { |
268 |
wcDir.mkdirs(); |
269 |
svnCManager.getUpdateClient() |
270 |
.doCheckout(reposUrl, wcDir, SVNRevision.HEAD, |
271 |
SVNRevision.HEAD, SVNDepth.INFINITY, true); |
272 |
result = true; |
273 |
} catch (Exception e) { |
274 |
err.println("Error while checking out a working copy for the location '" |
275 |
+ reposUrl + "': " + e.getMessage()); |
276 |
} |
277 |
return result; |
278 |
} |
279 |
} |