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
348 if ( changesetDate == null )
349 {
350 changesetDate = parseDate( date.toString(), userDateFormat, JAZZ_TIMESTAMP_PATTERN_TIME );
351
352 if ( changesetDate == null )
353 {
354 changesetDate =
355 parseDate( date.toString(), userDateFormat, JAZZ_TIMESTAMP_PATTERN_TIME, Locale.ENGLISH );
356 }
357
358 Calendar today = Calendar.getInstance();
359
360 Calendar changesetCal = Calendar.getInstance();
361
362 changesetCal.setTimeInMillis( changesetDate.getTime() );
363
364 changesetCal.set( today.get( Calendar.YEAR ), today.get( Calendar.MONTH ),
365 today.get( Calendar.DAY_OF_MONTH ) );
366
367 changesetDate = changesetCal.getTime();
368 }
369
370 if ( getLogger().isDebugEnabled() )
371 {
372 getLogger().debug( " date : " + date );
373 getLogger().debug( " changesetDate : " + changesetDate );
374 }
375
376 ChangeSet currentChangeSet = entries.get( currentChangeSetIndex );
377 currentChangeSet.setDate( changesetDate );
378 }
379 }
380
381 private void processChangesLine( String line )
382 {
383
384
385
386
387
388 Matcher matcher = CHANGES_PATTERN.matcher( line );
389 if ( matcher.find() )
390 {
391 ChangeSet currentChangeSet = entries.get( currentChangeSetIndex );
392
393 String changeFlags = matcher.group( 1 );
394 String fileAlias = matcher.group( 2 );
395 String file = matcher.group( 3 );
396
397 if ( getLogger().isDebugEnabled() )
398 {
399 getLogger().debug( " Parsing Changes Line : " + line );
400 getLogger().debug(
401 " changeFlags : " + changeFlags + " Translated to : " + parseFileChangeState( changeFlags ) );
402 getLogger().debug( " filetAlias : " + fileAlias );
403 getLogger().debug( " file : " + file );
404 }
405
406 ChangeFile changeFile = new ChangeFile( file );
407 ScmFileStatus status = parseFileChangeState( changeFlags );
408 changeFile.setAction( status );
409 currentChangeSet.getFiles().add( changeFile );
410 }
411 }
412
413
414
415
416
417
418
419 protected String stripDelimiters( String text )
420 {
421 if ( text == null )
422 {
423 return null;
424 }
425 String workingText = text;
426 if ( workingText.startsWith( "\"" ) || workingText.startsWith( "<" ) )
427 {
428 workingText = workingText.substring( 1 );
429 }
430 if ( workingText.endsWith( "\"" ) || workingText.endsWith( ">" ) )
431 {
432 workingText = workingText.substring( 0, workingText.length() - 1 );
433 }
434
435 return workingText;
436 }
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451 private ScmFileStatus parseChangeSetChangeState( String state )
452 {
453 if ( state.length() != 4 )
454 {
455 throw new IllegalArgumentException( "Change State string must be 4 chars long!" );
456 }
457
458
459 return ScmFileStatus.UNKNOWN;
460 }
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480 private ScmFileStatus parseFileChangeState( String state )
481 {
482 if ( state.length() != 5 )
483 {
484 throw new IllegalArgumentException( "Change State string must be 5 chars long!" );
485 }
486
487
488
489
490
491 ScmFileStatus status = ScmFileStatus.UNKNOWN;
492
493
494 if ( state.charAt( 0 ) == '!' )
495 {
496 status = ScmFileStatus.CONFLICT;
497 }
498
499 if ( state.charAt( 1 ) == '#' )
500 {
501 status = ScmFileStatus.CONFLICT;
502 }
503
504
505
506
507 if ( state.charAt( 2 ) == 'a' )
508 {
509 status = ScmFileStatus.ADDED;
510 }
511 else
512 {
513 if ( state.charAt( 2 ) == 'd' )
514 {
515 status = ScmFileStatus.DELETED;
516 }
517 else
518 {
519 if ( state.charAt( 2 ) == 'm' )
520 {
521 status = ScmFileStatus.RENAMED;
522 }
523
524
525 if ( state.charAt( 3 ) == 'c' )
526 {
527 status = ScmFileStatus.MODIFIED;
528 }
529
530
531 if ( state.charAt( 4 ) == 'p' )
532 {
533 status =
534 ScmFileStatus.MODIFIED;
535 }
536 }
537 }
538
539 return status;
540 }
541 }