1 package org.apache.maven.scm.provider.jazz.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.log.ScmLogger;
26 import org.apache.maven.scm.provider.ScmProviderRepository;
27 import org.apache.maven.scm.provider.jazz.command.consumer.AbstractRepositoryConsumer;
28
29 import java.util.ArrayList;
30 import java.util.Calendar;
31 import java.util.Date;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.regex.Matcher;
35 import java.util.regex.Pattern;
36
37
38
39
40
41
42
43
44
45 public class JazzListChangesetConsumer
46 extends AbstractRepositoryConsumer
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 private static final int STATE_CHANGE_SETS = 0;
121
122 private static final int STATE_CHANGE_SET = 1;
123
124 private static final int STATE_COMPONENT = 2;
125
126 private static final int STATE_MODIFIED = 3;
127
128 private static final int STATE_CHANGES = 4;
129
130
131 private static final String HEADER_CHANGE_SETS = "Change sets:";
132
133 private static final String HEADER_CHANGE_SET = "(";
134
135 private static final String HEADER_COMPONENT = "Component:";
136
137 private static final String HEADER_MODIFIED = "Modified:";
138
139 private static final String HEADER_CHANGES = "Changes:";
140
141 private static final String JAZZ_TIMESTAMP_PATTERN = "MMM d, yyyy h:mm a";
142
143
144 private static final String JAZZ_TIMESTAMP_PATTERN_TIME = "h:mm a";
145
146
147
148
149 private static final Pattern CHANGESET_PATTERN = Pattern.compile( "\\((\\d+)\\) (....) (\\w+) (.*)" );
150
151
152
153
154
155 private static final Pattern CHANGES_PATTERN = Pattern.compile( "(.....) \\((\\d+)\\) (.*)" );
156
157
158 private List<ChangeSet> entries;
159
160 private final String userDateFormat;
161
162
163
164 private int currentChangeSetIndex = -1;
165
166 private int currentState = STATE_CHANGE_SETS;
167
168
169
170
171
172
173
174
175 public JazzListChangesetConsumer( ScmProviderRepository repo, ScmLogger logger, List<ChangeSet> entries,
176 String userDateFormat )
177 {
178 super( repo, logger );
179 this.entries = entries;
180 this.userDateFormat = userDateFormat;
181 }
182
183
184
185
186
187
188
189 public void consumeLine( String line )
190 {
191 super.consumeLine( line );
192
193
194 if ( line.trim().startsWith( HEADER_CHANGE_SETS ) )
195 {
196 currentState = STATE_CHANGE_SETS;
197 }
198 else
199 {
200 if ( line.trim().startsWith( HEADER_CHANGE_SET ) )
201 {
202 currentState = STATE_CHANGE_SET;
203 }
204 else
205 {
206 if ( line.trim().startsWith( HEADER_COMPONENT ) )
207 {
208 currentState = STATE_COMPONENT;
209 }
210 else
211 {
212 if ( line.trim().startsWith( HEADER_MODIFIED ) )
213 {
214 currentState = STATE_MODIFIED;
215 }
216 else
217 {
218 if ( line.trim().startsWith( HEADER_CHANGES ) )
219 {
220
221
222
223
224
225
226
227 currentState = STATE_CHANGES;
228 }
229 }
230 }
231 }
232 }
233
234 switch ( currentState )
235 {
236 case STATE_CHANGE_SETS:
237
238 break;
239
240 case STATE_CHANGE_SET:
241 processChangeSetLine( line );
242 break;
243
244 case STATE_COMPONENT:
245
246 break;
247
248 case STATE_MODIFIED:
249 processModifiedLine( line );
250 break;
251
252 case STATE_CHANGES:
253 processChangesLine( line );
254 break;
255
256 default:
257 }
258
259 }
260
261 private void processChangeSetLine( String line )
262 {
263
264
265
266 Matcher matcher = CHANGESET_PATTERN.matcher( line );
267 if ( matcher.find() )
268 {
269
270
271 currentChangeSetIndex++;
272 ChangeSet currentChangeSet = entries.get( currentChangeSetIndex );
273
274
275 List<ChangeFile> files = new ArrayList<ChangeFile>();
276 currentChangeSet.setFiles( files );
277
278 String changesetAlias = matcher.group( 1 );
279 String changeFlags = matcher.group( 2 );
280 String author = matcher.group( 3 );
281 String comment = matcher.group( 4 );
282
283 if ( getLogger().isDebugEnabled() )
284 {
285 getLogger().debug( " Parsing ChangeSet Line : " + line );
286 getLogger().debug( " changesetAlias : " + changesetAlias );
287 getLogger().debug( " changeFlags : " + changeFlags );
288 getLogger().debug( " author : " + author );
289 getLogger().debug( " comment : " + comment );
290 }
291
292
293 if ( currentChangeSet.getRevision() != null && !currentChangeSet.getRevision().equals( changesetAlias ) )
294 {
295 getLogger().warn( "Warning! The indexes appear to be out of sequence! "
296 + "For currentChangeSetIndex = " + currentChangeSetIndex + ", we got '"
297 + changesetAlias + "' and not '" + currentChangeSet.getRevision()
298 + "' as expected." );
299 }
300
301 comment = stripDelimiters( comment );
302 currentChangeSet.setAuthor( author );
303 currentChangeSet.setComment( comment );
304 }
305 }
306
307 private void processModifiedLine( String line )
308 {
309
310
311
312
313
314
315
316 if ( getLogger().isDebugEnabled() )
317 {
318 getLogger().debug( " Parsing Modified Line : " + line );
319 }
320
321 int colonPos = line.indexOf( ":" );
322 int parenPos = line.indexOf( "(" );
323
324 String date = null;
325
326 if ( colonPos != -1 && parenPos != -1 )
327 {
328 date = line.substring( colonPos + 2, parenPos - 1 );
329 }
330 else
331 {
332 if ( colonPos != -1 && parenPos == -1 )
333 {
334
335 date = line.substring( colonPos + 2 );
336 }
337 }
338
339 if ( date != null )
340 {
341 Date changesetDate = parseDate( date.toString(), userDateFormat, JAZZ_TIMESTAMP_PATTERN );
342
343 if ( changesetDate == null )
344 {
345 changesetDate = parseDate( date.toString(), userDateFormat, JAZZ_TIMESTAMP_PATTERN, Locale.ENGLISH );
346 }
347 if ( changesetDate == null )
348 {
349
350 changesetDate = parseDate( date.toString(), userDateFormat, JAZZ_TIMESTAMP_PATTERN_TIME );
351
352 Calendar today = Calendar.getInstance();
353
354 Calendar changesetCal = Calendar.getInstance();
355
356 changesetCal.setTimeInMillis( changesetDate.getTime() );
357
358 changesetCal.set( today.get( Calendar.YEAR ), today.get( Calendar.MONTH ),
359 today.get( Calendar.DAY_OF_MONTH ) );
360
361 changesetDate = changesetCal.getTime();
362 }
363
364 if ( getLogger().isDebugEnabled() )
365 {
366 getLogger().debug( " date : " + date );
367 getLogger().debug( " changesetDate : " + changesetDate );
368 }
369
370 ChangeSet currentChangeSet = entries.get( currentChangeSetIndex );
371 currentChangeSet.setDate( changesetDate );
372 }
373 }
374
375 private void processChangesLine( String line )
376 {
377
378
379
380
381
382 Matcher matcher = CHANGES_PATTERN.matcher( line );
383 if ( matcher.find() )
384 {
385 ChangeSet currentChangeSet = entries.get( currentChangeSetIndex );
386
387 String changeFlags = matcher.group( 1 );
388 String fileAlias = matcher.group( 2 );
389 String file = matcher.group( 3 );
390
391 if ( getLogger().isDebugEnabled() )
392 {
393 getLogger().debug( " Parsing Changes Line : " + line );
394 getLogger().debug(
395 " changeFlags : " + changeFlags + " Translated to : " + parseFileChangeState( changeFlags ) );
396 getLogger().debug( " filetAlias : " + fileAlias );
397 getLogger().debug( " file : " + file );
398 }
399
400 ChangeFile changeFile = new ChangeFile( file );
401 ScmFileStatus status = parseFileChangeState( changeFlags );
402 changeFile.setAction( status );
403 currentChangeSet.getFiles().add( changeFile );
404 }
405 }
406
407
408
409
410
411
412
413 protected String stripDelimiters( String text )
414 {
415 if ( text == null )
416 {
417 return null;
418 }
419 String workingText = text;
420 if ( workingText.startsWith( "\"" ) || workingText.startsWith( "<" ) )
421 {
422 workingText = workingText.substring( 1 );
423 }
424 if ( workingText.endsWith( "\"" ) || workingText.endsWith( ">" ) )
425 {
426 workingText = workingText.substring( 0, workingText.length() - 1 );
427 }
428
429 return workingText;
430 }
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445 private ScmFileStatus parseChangeSetChangeState( String state )
446 {
447 if ( state.length() != 4 )
448 {
449 throw new IllegalArgumentException( "Change State string must be 4 chars long!" );
450 }
451
452
453 return ScmFileStatus.UNKNOWN;
454 }
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474 private ScmFileStatus parseFileChangeState( String state )
475 {
476 if ( state.length() != 5 )
477 {
478 throw new IllegalArgumentException( "Change State string must be 5 chars long!" );
479 }
480
481
482
483
484
485 ScmFileStatus status = ScmFileStatus.UNKNOWN;
486
487
488 if ( state.charAt( 0 ) == '!' )
489 {
490 status = ScmFileStatus.CONFLICT;
491 }
492
493 if ( state.charAt( 1 ) == '#' )
494 {
495 status = ScmFileStatus.CONFLICT;
496 }
497
498
499
500
501 if ( state.charAt( 2 ) == 'a' )
502 {
503 status = ScmFileStatus.ADDED;
504 }
505 else
506 {
507 if ( state.charAt( 2 ) == 'd' )
508 {
509 status = ScmFileStatus.DELETED;
510 }
511 else
512 {
513 if ( state.charAt( 2 ) == 'm' )
514 {
515 status = ScmFileStatus.RENAMED;
516 }
517
518
519 if ( state.charAt( 3 ) == 'c' )
520 {
521 status = ScmFileStatus.MODIFIED;
522 }
523
524
525 if ( state.charAt( 4 ) == 'p' )
526 {
527 status =
528 ScmFileStatus.MODIFIED;
529 }
530 }
531 }
532
533 return status;
534 }
535 }