/
SubversionEventHandlerImpl.java
224 lines (205 loc) · 8.25 KB
/
SubversionEventHandlerImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
* ====================================================================
* Copyright (c) 2004-2007 TMate Software Ltd. All rights reserved.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://svnkit.com/license.html
* If newer versions of this license are posted there, you may use a
* newer version instead, at your option.
* ====================================================================
*/
package hudson.scm;
import org.tmatesoft.svn.core.SVNErrorCode;
import org.tmatesoft.svn.core.SVNErrorMessage;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.internal.util.SVNPathUtil;
import org.tmatesoft.svn.core.internal.wc.SVNFileUtil;
import org.tmatesoft.svn.core.wc.SVNEvent;
import org.tmatesoft.svn.core.wc.SVNEventAction;
import org.tmatesoft.svn.core.wc.SVNEventAdapter;
import org.tmatesoft.svn.core.wc.SVNStatusType;
import org.tmatesoft.svn.core.wc.ISVNEventHandler;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
/**
* {@link ISVNEventHandler} that emulates the SVN CLI behavior.
*
* @author Kohsuke Kawaguchi
*/
public class SubversionEventHandlerImpl extends SVNEventAdapter {
protected final PrintStream out;
protected final File baseDir;
public SubversionEventHandlerImpl(PrintStream out, File baseDir) {
this.out = out;
this.baseDir = baseDir;
}
public void handleEvent(SVNEvent event, double progress) throws SVNException {
File file = event.getFile();
String path = null;
if (file != null) {
try {
path = getRelativePath(file);
} catch (IOException e) {
throw new SVNException(SVNErrorMessage.create(SVNErrorCode.FS_GENERAL, e));
}
path = getLocalPath(path);
}
SVNEventAction action = event.getAction();
{// commit notifications
if (action == SVNEventAction.COMMIT_ADDED) {
out.println("Adding " + path);
return;
}
if (action == SVNEventAction.COMMIT_DELETED) {
out.println("Deleting " + path);
return;
}
if (action == SVNEventAction.COMMIT_MODIFIED) {
out.println("Sending " + path);
return;
}
if (action == SVNEventAction.COMMIT_REPLACED) {
out.println("Replacing " + path);
return;
}
if (action == SVNEventAction.COMMIT_DELTA_SENT) {
out.println("Transmitting file data....");
return;
}
}
String pathChangeType = " ";
if (action == SVNEventAction.UPDATE_ADD) {
pathChangeType = "A";
SVNStatusType contentsStatus = event.getContentsStatus();
if(contentsStatus== SVNStatusType.UNCHANGED) {
// happens a lot with merges
pathChangeType = " ";
}else if (contentsStatus == SVNStatusType.CONFLICTED) {
pathChangeType = "C";
} else if (contentsStatus == SVNStatusType.MERGED) {
pathChangeType = "G";
}
} else if (action == SVNEventAction.UPDATE_DELETE) {
pathChangeType = "D";
} else if (action == SVNEventAction.UPDATE_UPDATE) {
SVNStatusType contentsStatus = event.getContentsStatus();
if (contentsStatus == SVNStatusType.CHANGED) {
/*
* the item was modified in the repository (got the changes
* from the repository
*/
pathChangeType = "U";
} else if (contentsStatus == SVNStatusType.CONFLICTED) {
/*
* The file item is in a state of Conflict. That is, changes
* received from the repository during an update, overlap with
* local changes the user has in his working copy.
*/
pathChangeType = "C";
} else if (contentsStatus == SVNStatusType.MERGED) {
/*
* The file item was merGed (those changes that came from the
* repository did not overlap local changes and were merged
* into the file).
*/
pathChangeType = "G";
}
} else if (action == SVNEventAction.UPDATE_COMPLETED) {
// finished updating
out.println("At revision " + event.getRevision());
out.println();
return;
} else if (action == SVNEventAction.ADD){
out.println("A " + path);
return;
} else if (action == SVNEventAction.DELETE){
out.println("D " + path);
return;
} else if (action == SVNEventAction.LOCKED){
out.println("L " + path);
return;
} else if (action == SVNEventAction.LOCK_FAILED){
out.println("failed to lock " + path);
return;
}
/*
* Now getting the status of properties of an item. SVNStatusType also
* contains information on the properties state.
*/
SVNStatusType propertiesStatus = event.getPropertiesStatus();
String propertiesChangeType = " ";
if (propertiesStatus == SVNStatusType.CHANGED) {
propertiesChangeType = "U";
} else if (propertiesStatus == SVNStatusType.CONFLICTED) {
propertiesChangeType = "C";
} else if (propertiesStatus == SVNStatusType.MERGED) {
propertiesChangeType = "G";
}
String lockLabel = " ";
SVNStatusType lockType = event.getLockStatus();
if (lockType == SVNStatusType.LOCK_UNLOCKED) {
// The lock is broken by someone.
lockLabel = "B";
}
if(pathChangeType.equals(" ") && propertiesChangeType.equals(" ") && lockLabel.equals(" "))
// nothing to display here.
return;
out.println(pathChangeType
+ propertiesChangeType
+ lockLabel
+ " "
+ path);
}
public String getRelativePath(File file) throws IOException {
String inPath = file.getCanonicalPath().replace(File.separatorChar, '/');
String basePath = baseDir.getCanonicalPath().replace(File.separatorChar, '/');
String commonRoot = getCommonAncestor(inPath, basePath);
String relativePath = inPath;
if (commonRoot != null) {
if (equals(inPath , commonRoot)) {
return "";
} else if (startsWith(inPath, commonRoot + "/")) {
relativePath = inPath.substring(commonRoot.length() + 1);
}
}
if (relativePath.endsWith("/")) {
relativePath = relativePath.substring(0, relativePath.length() - 1);
}
return relativePath;
}
private static String getCommonAncestor(String p1, String p2) {
if (SVNFileUtil.isWindows || SVNFileUtil.isOpenVMS) {
String ancestor = SVNPathUtil.getCommonPathAncestor(p1.toLowerCase(), p2.toLowerCase());
if (equals(ancestor, p1)) {
return p1;
} else if (equals(ancestor, p2)) {
return p2;
} else if (startsWith(p1, ancestor)) {
return p1.substring(0, ancestor.length());
}
return ancestor;
}
return SVNPathUtil.getCommonPathAncestor(p1, p2);
}
private static boolean startsWith(String p1, String p2) {
if (SVNFileUtil.isWindows || SVNFileUtil.isOpenVMS) {
return p1.toLowerCase().startsWith(p2.toLowerCase());
}
return p1.startsWith(p2);
}
private static boolean equals(String p1, String p2) {
if (SVNFileUtil.isWindows || SVNFileUtil.isOpenVMS) {
return p1.toLowerCase().equals(p2.toLowerCase());
}
return p1.equals(p2);
}
public static String getLocalPath(String path) {
path = path.replace('/', File.separatorChar);
if ("".equals(path)) {
path = ".";
}
return path;
}
}