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