1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.scm.provider.svn.svnexe.command.changelog;
20
21 import java.util.ArrayList;
22 import java.util.Date;
23 import java.util.List;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 import org.apache.maven.scm.ChangeFile;
28 import org.apache.maven.scm.ChangeSet;
29 import org.apache.maven.scm.ScmFileStatus;
30 import org.apache.maven.scm.provider.svn.SvnChangeSet;
31 import org.apache.maven.scm.util.AbstractConsumer;
32
33
34
35
36
37 public class SvnChangeLogConsumer extends AbstractConsumer {
38
39
40
41 private static final String SVN_TIMESTAMP_PATTERN = "yyyy-MM-dd HH:mm:ss zzzzzzzzz";
42
43
44
45
46 private static final int GET_HEADER = 1;
47
48
49
50
51 private static final int GET_FILE = 2;
52
53
54
55
56 private static final int GET_COMMENT = 3;
57
58
59
60
61 private static final Pattern FILE_PATTERN = Pattern.compile("^\\s\\s\\s([A-Z])\\s(.+)$");
62
63
64
65
66
67 private static final Pattern ORIG_FILE_PATTERN = Pattern.compile("\\([A-Za-z]+ (.+):(\\d+)\\)");
68
69
70
71
72 private static final String FILE_END_TOKEN = "";
73
74
75
76
77 private static final String COMMENT_END_TOKEN =
78 "------------------------------------" + "------------------------------------";
79
80
81
82
83 private int status = GET_HEADER;
84
85
86
87
88 private final List<ChangeSet> entries = new ArrayList<>();
89
90
91
92
93 private SvnChangeSet currentChange;
94
95
96
97
98 private String currentRevision;
99
100
101
102
103 private StringBuilder currentComment;
104
105
106
107
108 private static final Pattern HEADER_REG_EXP = Pattern.compile("^(.+) \\| (.+) \\| (.+) \\|.*$");
109
110 private static final int REVISION_GROUP = 1;
111
112 private static final int AUTHOR_GROUP = 2;
113
114 private static final int DATE_GROUP = 3;
115
116 private static final Pattern REVISION_REG_EXP1 = Pattern.compile("rev (\\d+):");
117
118 private static final Pattern REVISION_REG_EXP2 = Pattern.compile("r(\\d+)");
119
120 private static final Pattern DATE_REG_EXP = Pattern.compile("(\\d+-\\d+-\\d+ " +
121 "\\d+:\\d+:\\d+) "
122 +
123 "([\\-+])(\\d\\d)(\\d\\d)");
124
125 private final String userDateFormat;
126
127
128
129
130 public SvnChangeLogConsumer(String userDateFormat) {
131 this.userDateFormat = userDateFormat;
132 }
133
134 public List<ChangeSet> getModifications() {
135 return entries;
136 }
137
138
139
140
141
142
143
144
145 public void consumeLine(String line) {
146 if (logger.isDebugEnabled()) {
147 logger.debug(line);
148 }
149 switch (status) {
150 case GET_HEADER:
151 processGetHeader(line);
152 break;
153 case GET_FILE:
154 processGetFile(line);
155 break;
156 case GET_COMMENT:
157 processGetComment(line);
158 break;
159 default:
160 throw new IllegalStateException("Unknown state: " + status);
161 }
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177 private void processGetHeader(String line) {
178 Matcher matcher = HEADER_REG_EXP.matcher(line);
179 if (!matcher.matches()) {
180
181 return;
182 }
183
184 currentRevision = getRevision(matcher.group(REVISION_GROUP));
185
186 currentChange = new SvnChangeSet();
187
188 currentChange.setAuthor(matcher.group(AUTHOR_GROUP));
189
190 currentChange.setDate(getDate(matcher.group(DATE_GROUP)));
191
192 currentChange.setRevision(currentRevision);
193
194 status = GET_FILE;
195 }
196
197
198
199
200
201
202
203 private String getRevision(final String revisionOutput) {
204 Matcher matcher;
205 if ((matcher = REVISION_REG_EXP1.matcher(revisionOutput)).matches()) {
206 return matcher.group(1);
207 } else if ((matcher = REVISION_REG_EXP2.matcher(revisionOutput)).matches()) {
208 return matcher.group(1);
209 } else {
210 throw new IllegalOutputException(revisionOutput);
211 }
212 }
213
214
215
216
217
218
219
220
221
222 private void processGetFile(String line) {
223 Matcher matcher = FILE_PATTERN.matcher(line);
224 if (matcher.matches()) {
225 final String fileinfo = matcher.group(2);
226 String name = fileinfo;
227 String originalName = null;
228 String originalRev = null;
229 final int n = fileinfo.indexOf(" (");
230 if (n > 1 && fileinfo.endsWith(")")) {
231 final String origFileInfo = fileinfo.substring(n);
232 Matcher matcher2 = ORIG_FILE_PATTERN.matcher(origFileInfo);
233 if (matcher2.find()) {
234
235 name = fileinfo.substring(0, n);
236 originalName = matcher2.group(1);
237 originalRev = matcher2.group(2);
238 }
239 }
240 final String actionStr = matcher.group(1);
241 final ScmFileStatus action;
242 if ("A".equals(actionStr)) {
243
244 action = originalRev == null ? ScmFileStatus.ADDED : ScmFileStatus.COPIED;
245 } else if ("D".equals(actionStr)) {
246 action = ScmFileStatus.DELETED;
247 } else if ("M".equals(actionStr)) {
248 action = ScmFileStatus.MODIFIED;
249 } else if ("R".equals(actionStr)) {
250 action = ScmFileStatus.UPDATED;
251 } else {
252 action = ScmFileStatus.UNKNOWN;
253 }
254 if (logger.isDebugEnabled()) {
255 logger.debug(actionStr + " : " + name);
256 }
257 final ChangeFile changeFile = new ChangeFile(name, currentRevision);
258 changeFile.setAction(action);
259 changeFile.setOriginalName(originalName);
260 changeFile.setOriginalRevision(originalRev);
261 currentChange.addFile(changeFile);
262
263 status = GET_FILE;
264 } else if (line.equals(FILE_END_TOKEN)) {
265
266
267 currentComment = new StringBuilder();
268
269 status = GET_COMMENT;
270 }
271 }
272
273
274
275
276
277
278
279 private void processGetComment(String line) {
280 if (line.equals(COMMENT_END_TOKEN)) {
281 currentChange.setComment(currentComment.toString());
282
283 entries.add(currentChange);
284
285 status = GET_HEADER;
286 } else {
287 currentComment.append(line).append('\n');
288 }
289 }
290
291
292
293
294
295
296
297
298 private Date getDate(final String dateOutput) {
299 Matcher matcher = DATE_REG_EXP.matcher(dateOutput);
300 if (!matcher.find()) {
301 throw new IllegalOutputException(dateOutput);
302 }
303
304 final StringBuilder date = new StringBuilder();
305 date.append(matcher.group(1));
306 date.append(" GMT");
307 date.append(matcher.group(2));
308 date.append(matcher.group(3));
309 date.append(':');
310 date.append(matcher.group(4));
311
312 return parseDate(date.toString(), userDateFormat, SVN_TIMESTAMP_PATTERN);
313 }
314 }